The methods in user mode are: atomic operations (e.g. a single global variable), critical section.
The methods in kernel mode are: event, semaphore, mutex.
Critical section
An easy way to ensure that only one thread can access the data at a time. Only one thread is allowed to access the shared resource at any time. If more than one thread attempts to access the critical section at the same time, all other threads that attempt to access this critical section after one thread has entered will be suspended and continue until the thread entering the critical section leaves. When the critical section is released, other threads can continue to preempt, and in this way achieve the purpose of atomic manipulation of shared resources. can only be used within the same process
Mutex Mutex
The mutex is similar to the critical section, and only the line friend with the mutex has permission to access the resource, because there is only one mutex object, so it is determined that the shared resource will not be accessed by multiple threads at the same time in any case. The thread that currently occupies the resource should hand over the owning mutex after the task has been processed so that other threads can access the resource after it is acquired. The mutex is more complex than the critical section. Because using mutexes not only enables the secure sharing of resources in different threads of the same application, but also enables secure sharing of resources between threads of different applications .
Signal Volume
Semaphore objects synchronize threads differently than in the previous methods, and the signal allows multiple threads to use shared resources at the same time as the PV operation in the operating system.
Events (Event)
Event mechanism, a thread is allowed to actively wake up another thread to perform a task after it has finished processing a task.
The above methods have different APIs under win and Linux
APIs for synchronizing under Linux: Mutex mutex
- Initializes the lock. Under Linux, the mutex data type of a thread is pthread_mutex_t. Before you use it, initialize it.
Static assignment: pthread_mutex_t mutex = Pthread_mutex_initializer;
Dynamic assignment: int pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutex_attr_t *mutexattr);
- Locking Access to the shared resource is to lock the mutex, and if the mutex is already locked, the calling thread blocks until the mutex is unlocked.
int Pthread_mutex_lock (Pthread_mutex *mutex);
int Pthread_mutex_trylock (pthread_mutex_t *mutex);
- Unlock. After the access to the shared resource has been completed, the mutex is unlocked.
int Pthread_mutex_unlock (pthread_mutex_t *mutex);
- Destroys the lock. After the lock is complete, it needs to be destroyed to free up resources.
int Pthread_mutex_destroy (Pthread_mutex *mutex);
Signal Volume (SEM)
As with processes, threads can also communicate through semaphores, albeit in a lightweight way. The semaphore function names begin with "Sem_". There are four basic semaphore functions used by the thread.
- Initialization of the signal volume.
int Sem_init (sem_t *sem, int pshared, unsigned int value);
This is the initialization of the semaphore specified by the SEM, set its sharing options (Linux only supports 0, that is, it is the local semaphore of the current process), and then gives it an initial value of values.
- Wait for the semaphore. Reduce the semaphore by 1 and wait until the semaphore value is greater than 0.
int sem_wait (sem_t *sem);
- Releases the semaphore. Semaphore value plus 1. and notifies other waiting threads.
int Sem_post (sem_t *sem);
- Destroys the semaphore. We use the semaphore to clean it up. Return all the resources in possession.
int Sem_destroy (sem_t *sem);
Condition variable (COND)
Unlike mutex locks, conditional variables are used to wait instead of locked. a condition variable is used to automatically block a thread until a particular situation occurs. Usually the condition variable and the mutex are used together . The condition variable is divided into two parts: conditions and variables. The condition itself is protected by a mutex. The thread locks the mutex before changing the condition state. Condition variables allow us to sleep and wait for a certain condition to appear. A conditional variable is a mechanism for synchronizing a global variable shared between threads, which consists of two actions: one thread waits for the condition variable to be set up, and the other thread causes the condition to be set. The condition detection is performed under the protection of the mutex. If a condition is false, a thread automatically blocks and releases the mutex that waits for the state to change. If another thread changes the condition, it signals to the associated condition variable, wakes one or more threads waiting for it, re-obtains the mutex, and re-evaluates the condition. If two processes share read-write memory, the condition variable can be used to implement thread synchronization between the two processes.
- Initializes the condition variable.
Static state initialization, pthread_cond_t cond = Pthread_cond_initialier;
Dynamic initialization, int pthread_cond_init (pthread_cond_t *cond, pthread_condattr_t *cond_attr);
- Wait for the condition to be established. Release the lock while blocking the wait condition variable to true. Timewait () Set wait time, still not signal, return Etimeout (lock guarantee only one thread wait)
int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timewait (pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);
- Activates the condition variable. Pthread_cond_signal,pthread_cond_broadcast (activates all waiting threads)
int pthread_cond_signal (pthread_cond_t *cond);
int Pthread_cond_broadcast (pthread_cond_t *cond); Remove all threads from blocking
- Clears the condition variable. Wireless path Wait, otherwise return ebusy
int Pthread_cond_destroy (pthread_cond_t *cond);
Three ways to refer to Linux thread synchronization
The API to achieve synchronization under win:
Critical Area (Critical section)
EnterCriticalSection () Enter the critical section
LeaveCriticalSection () Leave the critical section
Mutex (mutex)
CreateMutex () creates a mutex
OpenMutex () Open a mutex
ReleaseMutex () Release mutex
WaitForMultipleObjects () waits for mutex object
signal Volume (semaphores)
CreateSemaphore () Create a semaphore
OpenSemaphore () Open a semaphore
ReleaseSemaphore () Release semaphore
WaitForSingleObject () wait for the semaphore
Events (Event)
CreateEvent () Create an event
OpenEvent () Open an event
SetEvent () Reset Event
WaitForSingleObject () waits for an event
WaitForMultipleObjects () waits for multiple events
Win under mutual exclusion and critical area difference
|
Mutex |
Critical section |
Performance and Speed |
Slow. a Mutex is a kernel object , the execution of a related function (WaitForSingleObject, ReleaseMutex) requires user mode to kernel mode (Kernel Mode), the conversion on the x86 processor is generally About 600 CPU instruction cycles. |
Fast. The Critical section itself is not a kernel object, and the correlation function (entercriticalsection,leavecriticalsection) are typically executed in user mode , on the x86 processor Generally, only about 9 CPU instruction cycles are required. Only It degrades when the lock you want to get is just owned by another thread. Sing Woo mutex, that is, conversion to kernel mode, the cost of 600 Around the CPU instruction cycle. |
Can cross process boundaries |
OK |
Not |
Define the wording |
HANDLE hmtx; |
Critical_section CS; |
Initialize the wording of the |
Hmtx= CreateMutex (NULL, FALSE, NULL); |
InitializeCriticalSection (&CS); |
End Clear Spelling |
CloseHandle (HMTX); |
DeleteCriticalSection (&CS); |
How to wait indefinitely |
WaitForSingleObject (HMTX, INFINITE); |
EnterCriticalSection (&CS); |
0 Waiting (status detection) notation |
WaitForSingleObject (hmtx, 0); |
TryEnterCriticalSection (&CS); |
Any time to wait for the wording |
WaitForSingleObject (HMTX, dwmilliseconds); |
Not supported |
The wording of the lock release |
ReleaseMutex (HMTX); |
LeaveCriticalSection (&CS); |
Can be used together to wait for other kernel objects |
Yes (using WaitForMultipleObjects, WaitForMultipleObjectsEx, MsgWaitForMultipleObjects, Msgwaitformultipleobjectsex, etc.) |
Not |
When the thread that owns the lock dies |
The mutex becomes abandoned state, and other waiting threads can get the lock. |
The state of the Critical section is not known (undefined), There is no guarantee of future action. |
Will you lock yourself up? |
No (repeated calls to the acquired mutex, WaitForSingleObject, will not Lock yourself up. But in the end you don't forget to call the same number of ReleaseMutex) |
Not (repeated calls to the critical section that has been obtained EnterCriticalSection won't lock himself up. But in the end You don't forget to call the same number of LeaveCriticalSection) |
Comparison of thread synchronization methods