Inmulti-threadedcomputer programming, a function isthread-safe when it can be invoked or accessed concurrently by multiple threads without causing unexpected behavior,race conditions, ordata corruption.[1][2] As in the multi-threaded context where a program executes several threads simultaneously in a sharedaddress space and each of those threads has access to every other thread'smemory, thread-safe functions need to ensure that all those threads behave properly and fulfill their design specifications without unintended interaction.[3]
There are various strategies for making thread-safe data structures.[3]
Different vendors use slightly different terminology for thread-safety,[4] but the most commonly used thread-safety terminology are:[2]
Thread safety guarantees usually also include design steps to prevent or limit the risk of different forms ofdeadlocks, as well as optimizations to maximize concurrent performance. However, deadlock-free guarantees cannot always be given, since deadlocks can be caused bycallbacks and violation ofarchitectural layering independent of the library itself.
Software libraries can provide certain thread-safety guarantees.[5] For example, concurrent reads might be guaranteed to be thread-safe, but concurrent writes might not be. Whether a program using such a library is thread-safe depends on whether it uses the library in a manner consistent with those guarantees.
Listed are two classes of approaches for avoidingrace conditions to achieve thread-safety.
The first class of approaches focuses on avoiding shared state and includes:
The second class of approaches are synchronization-related, and are used in situations where shared state cannot be avoided:
In the following piece ofJava code, the Java keywordsynchronized makes the method thread-safe:
classCounter{privateinti=0;publicsynchronizedvoidinc(){i++;}}
In theC programming language, each thread has its own stack. However, astatic variable is not kept on the stack; all threads share simultaneous access to it. If multiple threads overlap while running the same function, it is possible that a static variable might be changed by one thread while another is midway through checking it. This difficult-to-diagnoselogic error, which may compile and run properly most of the time, is called arace condition. One common way to avoid this is to use another shared variable as a"lock" or "mutex" (frommutualexclusion).
In the following piece of C code which callsPOSIX headers, the function is thread-safe, but not reentrant:
#include<pthread.h>intincrementCounter(){staticintcounter=0;staticpthread_mutex_tmutex=PTHREAD_MUTEX_INITIALIZER;// only allow one thread to increment at a timepthread_mutex_lock(&mutex);++counter;// store value before any other threads increment it furtherintresult=counter;pthread_mutex_unlock(&mutex);returnresult;}
In the above,increment_counter can be called by different threads without any problem since a mutex is used to synchronize all access to the sharedcounter variable. But if the function is used in a reentrantinterrupt handler and a second interrupt arises while the mutex is locked, the second routine will hang forever. As interrupt servicing can disable other interrupts, the whole system could suffer.
The same function can be implemented to be both thread-safe and reentrant using the lock-freeatomics, which were introduced inC++11:
importstd;usingstd::atomic;intincrementCounter(){staticatomic<int>counter(0);// increment is guaranteed to be done atomicallyintresult=++counter;returnresult;}
{{cite book}}: CS1 maint: postscript (link){{cite web}}: CS1 maint: postscript (link){{cite web}}: CS1 maint: postscript (link)