Synchronization concept
Synchronization in communication refers to co synchronization, which runs in a predetermined order
Thread synchronization refers to when a thread makes a function call. The call will not return until the result is obtained. At the same time, other threads cannot call the data to ensure data consistency.
The purpose of "synchronization" is to avoid data confusion and solve time independent errors. In fact, synchronization is required not only between threads, but also between processes and signals.
Reasons for data confusion:
- resource sharing
- Scheduling random
- Lack of necessary synchronization mechanism between threads
Data confusion code
Two threads change a shared variable. It can be found that the shared variable counter is not incremented correctly between two threads.
#include "head.h" #define NOOP 500 int couter; void *doit(void *); int main(int argc, char* argv[]){ pthread_t tidA, tidB; pthread_create(&tidA, NULL, &doit, NULL); pthread_create(&tidB, NULL, &doit, NULL); pthread_join(tidA, NULL); pthread_join(tidB, NULL); exit(0); } void *doit(void *vptr){ int i, val; for(i = 0; i<NOOP;i++){ val = couter; printf("%lu:%d\n", pthread_self(),val+1); couter = val+1; } return (NULL); }
How to solve the problem of data confusion, a very simple solution is to use mutex
Mutex (mutex)
#include<pthread.h> int pthread_mutex_lock(pthread_mutex_t, *mptr); int pthread_mutex_unlock(pthread_mutex_t *mptr);
There are also the following functions
- pthread_mutex_init
- pthread_mutex_destory
- pthread_mutex_lock
- pthread_mutex_trylock / / try lock. If not, it will not block there
- pthread_mutex_unlock
Return value: 0 for success and error number for failure
matters needing attention:
Ensure the granularity of the lock, the smaller the better
Mutex: essentially a structure Locking: pthread_mutex_lock() ,Blocking thread Unlock: pthread_mutex_unlock(), Wake up the thread blocked on the lock. try Lock: try to lock and lock successfully; Failure directly returns the error number( EBUSY),No blocking
If you try to lock a mutex that has been locked by another thread, the thread will block until the mutex is unlocked
Static initialization and dynamic initialization
- If a mutex variable is statically allocated, we must initialize it to the constant PTHREAD_MUTEX_INITIALIZER
- If you allocate a mutex in a shared memory area, you must use pthread_ mutex_ The init function is initialized at run time.
//Corrected version #include "head.h" #define NOOP 500 int couter; pthread_mutex_t counter_mutex =PTHREAD_MUTEX_INITIALIZER; void *doit(void *); int main(int argc, char* argv[]){ pthread_t tidA, tidB; pthread_create(&tidA, NULL, &doit, NULL); pthread_create(&tidB, NULL, &doit, NULL); pthread_join(tidA, NULL); pthread_join(tidB, NULL); exit(0); } void *doit(void *vptr){ int i, val; for(i = 0; i<NOOP;i++){ pthread_mutex_lock(&counter_mutex); val = couter; printf("%lu:%d\n", pthread_self(),val+1); couter = val+1; pthread_mutex_unlock(&counter_mutex); } return (NULL); }
Read write lock properties
features:
- Read sharing, write exclusive
- Write lock priority high
- There is only one lock
- When the read-write lock is "write mode locking", all threads locking the lock will be blocked before unlocking
- When the read-write lock is "lock in read mode", if the thread locks it in read mode, it will succeed; If the thread is locked in write mode, it will block.
- When a read-write lock is "lock in read mode", there are both threads trying to lock in write mode and threads trying to lock in read mode. Then the read-write lock blocks subsequent read mode lock requests. Write mode lock is preferred. Read lock and write lock are blocked in parallel, and write lock has high priority.
Read / write locks are also called shared locks - exclusive locks. When the read-write lock is locked in read mode, it is locked in shared mode; When it is locked in write mode, it is locked in exclusive mode. Write exclusive, read shared
Read / write locks are ideal for reading more than writing data structures
deadlock
Is the use of locks inappropriate information
- Keep locking A lock (the thread attempts to lock A mutex A twice)
- Two threads hold one lock and request the other
Conditional variable
Mutexes are good for preventing simultaneous access to a shared variable, but we need something else that allows us to sleep while waiting for a condition to occur.
It is not a lock in itself, but it is usually used in combination with a lock. mutex
pthread_cond_t cond;
Initialize condition variable
pthread_mutex_t mutex;
- pthread_ mutex_ init(&mutex, NULL); dynamic initialization
- pthread_mutex_t mutex = PTHREAD_COND_INITIALIZER; initiate static
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict &mutex);
Function function:
1. The blocking waiting condition variable cond is satisfied
2. Releasing the mastered mutex is equivalent to pthread_ mutex_ unlock(&mutex)
1. 2 two steps are an atomic operation (i.e. inseparable)
3. When awakened, pthread_ cond_ When the wait function returns, unblock and re apply for pthread to obtain the mutex_ mutex_ lock(&mutex);
Semaphore
Equivalent to the initialization value is N Mutual exclusion of, N Value indicating the number of threads that can access the shared data area
sem_init
sem_destory
sem_wait corresponds to the locking of a mutex
sem_post corresponds to the unlocking of the mutex
sem_wait: 1. If the semaphore is greater than 0, the semaphore –
2. The semaphore is equal to 0, causing thread blocking
sem_post 1, the semaphore + + and wake up the thread blocked on the semaphore at the same time
The initial value of the semaphore determines the number of threads occupying the semaphore
Can be applied to threads and processes.
sem_init function
SYNOPSIS #include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value); //For pshared 0: Inter thread synchronization 1: Inter process synchronization //For value N Value that specifies the number of threads accessed simultaneously