Semaphores are used for multi-thread and multi-task synchronization. When a thread completes an action, it tells other threads through semaphores that other threads perform some actions (when everyone is in the semtake, ). The mutex lock is used for multi-thread multi-task mutex. If a thread occupies a certain resource, other threads cannot access it until the thread is unlocked and other threads can use the resource. For example, you may need to lock the access to global variables. After the operation is complete, you must unlock the global variables. Sometimes the lock and semaphore will be used at the same time"
That is to say, semaphores do not necessarily lock a certain resource, but are the concept of a process. For example, there are two threads A and B, thread B must wait for thread a to complete a task and then perform the following steps. This task does not necessarily lock a certain resource, or perform some computing or data processing. The thread mutex is the concept of "locking a resource". During the lock period, other threads cannot operate on the protected data. In some cases, the two are interchangeable.
Differences between the two:
Scope
Semaphore: process or thread (Linux only)
Mutex lock: between threads
Lock
Semaphores: as long as the semaphores value is greater than 0, other threads can successfully sem_wait, And the semaphores value minus one after success. If the value is not greater than 0, sem_wait is blocked until the value of sem_post is added after the release of sem_post.
Mutex lock: as long as it is locked, no other thread can access protected resources
Otherwise, it will be blocked.
The following are some concepts about traffic signals:
The main difference between a traffic signal and a mutex lock and a condition variable lies in the concept of a "lamp". When a lamp is on, resources are available, and when the lamp is off, the lights are unavailable. If the synchronization mode in the last two phases focuses on the "wait" operation, that is, the resource is unavailable, the traffic signal mechanism focuses on the lighting, that is, to inform the resource availability; it makes no sense to unlock a thread without waiting for it or to stimulate the conditions. The lighting operation of a thread without waiting for it is effective and can be kept on. Of course, such operation primitives also mean more overhead.
In addition to the binary lamp, the application of traffic signals can also use a lamp number greater than 1 to indicate that the number of resources is greater than 1.
1. Create and log out
POSIX signal lights are defined as well-known signal lights and unknown signal lights, but the implementation of linuxthreads only has unknown lights. Besides being well-known lights, they can always be used between multiple processes, there is no major difference between the use of lamps and lamps, so we will only discuss lamps.
Int sem_init (sem_t * SEM, int pshared, unsigned int value)
This is the API for creating traffic signals. value indicates the initial value of the traffic signal. pshared indicates whether to share the traffic signal with multiple processes rather than just one process. Linuxthreads does not implement multi-process shared traffic signals. Therefore, all non-0 pshared inputs will return-1 for sem_init () and set errno to enosys. The initialized signal lights are characterized by SEM variables and used for the following lighting and lamp removal operations.
Int sem_destroy (sem_t * SEM)
The canceled signal SEM requires that no thread is waiting for the signal. Otherwise,-1 is returned and errno is set to ebusy. In addition, threads's signal cancellation function does not perform any other action.
2. Lighting and lighting Removal
Int sem_post (sem_t * SEM)
The light-on operation adds 1 to the value of the signal lamp, indicating that an accessible resource is added.
Int sem_wait (sem_t * SEM)
Int sem_trywait (sem_t * SEM)
Sem_wait () is to wait for the light to shine, wait for the light to shine (the signal light value is greater than 0), then reduce the signal light by 1 and return. Sem_trywait () is a non-blocking version of sem_wait (). If the traffic signal count is greater than 0, 1 is reduced and 0 is returned. Otherwise,-1 is returned immediately, and errno is set to eagain.
3. Get the lamp Value
Int sem_getvalue (sem_t * SEM, int * sval)
Read the lamp count in SEM, save it in * sval, and return 0.
4. Miscellaneous
Sem_wait () is implemented as a cancellation point, and sem_post () in the architecture that supports atomic "comparison and exchange" commands () it is the only POSIX asynchronous signal security API that can be used for asynchronous signal processing functions.
----------------------------
Thread Synchronization: When is the mutex lock insufficient? Do I still need conditional variables?
Assume that there is a shared resource sum, and the associated mutex is lock_s. assume that the sum operation of each thread is very simple and irrelevant to the sum State. For example, it is only sum ++. only mutex is enough. the programmer only needs to ensure that the lock is obtained before each thread operation, sum ++, and unlock. the code for each thread will look like this
Add ()
{
Pthread_mutex_lock (lock_s );
Sum ++;
Pthread_mutex_unlock (lock_s );
}
If the operation is complex, assume that the operation of thread T0, T1, and T2 is sum ++, and thread T3 prints a message when sum reaches 100, and clears sum. in this case, if only mutex is used, T3 requires a loop. In each loop, lock_s is obtained first, and the sum state is checked. If sum> = 100, the data is printed and cleared, then unlock. if sum & amp; lt; 100, then unlock and sleep () This thread is appropriate for a period of time.
At this time, the code for T0, T1, and T2 remains unchanged. The code for T3 is as follows:
Print ()
{
While (1)
{
Pthread_mutex_lock (lock_s );
If (sum & lt; 100)
{
Printf ("sum reach 100 !");
Pthread_mutex_unlock (lock_s );
}
Else
{
Pthread_mutex_unlock (lock_s );
MySQL _ thread_sleep (100 );
Return OK;
}
}
}
There are two problems with this method.
1) sum will not reach 100 in most cases, so for the T3 code, in most cases, it takes the else branch, only lock and unlock, and then sleep (). this wastes CPU processing time.
2) To save CPU processing time, T3 will sleep () for a period of time when the sum has not reached 100. this brings about another problem, that is, the T3 response speed decreases. t4 may wake up when sum reaches 200.
3) in this way, the programmer is in a dilemma when setting sleep () time. It is too short to save resources, and it is too long to reduce the response speed. This is really hard to do!
At this time, condition variable underpants fell from the sky, saving you.
You first define a condition variable.
Pthread_cond_t cond_sum_ready = pthread_cond_initializer;
Code T0, T1, and T2 only needs to be followed by two lines, like this
Add ()
{
Pthread_mutex_lock (lock_s );
Sum ++;
Pthread_mutex_unlock (lock_s );
If (sum & gt; = 100)
Pthread_cond_signal (& cond_sum_ready );
}
The T3 code is
Print
{
Pthread_mutex_lock (lock_s );
While (sum <100)
Pthread_cond_wait (& cond_sum_ready, & lock_s );
Printf ("sum is over 100 !");
Sum = 0;
Pthread_mutex_unlock (lock_s );
Return OK;
}
Note:
1) Before thread_cond_wait (), you must first lock the associated mutex, because if the target condition is not met, pthread_cond_wait () will actually unlock the mutex, and then block, lock the mutex again after the target condition is met, and then return.
2) Why is it while (sum <100) instead of IF (sum <100 )? This is because there is a time difference between pthread_cond_signal () and pthread_cond_wait (). In this case, there is another thread T4 that reduces sum to less than 100, after pthread_cond_wait () is returned, T3 should check the sum size again. this is the intention of using while.