Linux advanced Programming--09. Thread Mutex and synchronization

Source: Internet
Author: User
Tags mutex semaphore usleep

Multiple threads may have conflicting access to shared data at the same time, for example, two threads have to increase a global variable by 1, which requires three instructions on a platform:

从内存读变量值到寄存器寄存器的值加1将寄存器的值写回内存

Assuming that two threads execute these three instructions concurrently on a multiprocessor platform, the result is shown, and the last variable is added only once, not two times.

The following example illustrates this process:

#include <stdio.h>#include <pthread.h>#include <unistd.h>int counter; /* incremented by threads */void *doit(void *vptr){    int i, val;    for (i = 0; i < 100; i++) {        val = counter;        usleep(1000);        counter = val + 1;    }    return NULL;}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);    printf("counter = %d \n", counter);    return 0;}

In this example, although each thread adds 100 to counter, the final output value is not 200, but 100 because of the overlap of results.

[email protected]:/mnt/share/test> runcounter = 100[email protected]:/mnt/share/test>
Mutex Mutex

For multi-threaded programs, the problem of access violations is common, the solution is to introduce a mutex (mutex,mutual Exclusive Lock), the thread that obtains the lock can complete the "read-Modify-write" operation, and then release the lock to other threads, A thread that does not have a lock can only wait for the shared data to be accessed, so that the "read-Modify-write" three-step operation consists of an atomic operation, either executed, either not executed, not executed in the middle, or done in parallel on the other processor.

There are several functions related to Mutext:

#include <pthread.h>pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;int pthread_mutex_destroy(pthread_mutex_t *mutex);int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);int pthread_mutex_lock(pthread_mutex_t *mutex);int pthread_mutex_trylock(pthread_mutex_t *mutex);int pthread_mutex_unlock(pthread_mutex_t *mutex);

From the name of the basic can be seen how to use, here is just the example above, with a mutex to transform it:

#include <stdio.h>#include <pthread.h>#include <unistd.h>int counter; /* incremented by threads */pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;void *doit(void *vptr){    int i, val;    for (i = 0; i < 100; i++) {        pthread_mutex_lock(&counter_mutex);        val = counter;        usleep(1000);        counter = val + 1;        pthread_mutex_unlock(&counter_mutex);    }    return NULL;}int main(int argc, char **argv){    pthread_mutex_init(&counter_mutex, NULL);    pthread_t tidA, tidB;    pthread_create(&tidA, NULL, &doit, NULL);    pthread_create(&tidB, NULL, &doit, NULL);    pthread_join(tidA, NULL);    pthread_join(tidB, NULL);    pthread_mutex_destroy(&counter_mutex);    printf("counter = %d \n", counter);    return 0;}

The results of this operation are correct:

[email protected]:/mnt/share/test> runcounter = 200[email protected]:/mnt/share/test>
Conditional variable Condtion

The Mutext described earlier is mainly used to implement mutual exclusion, and in multi-threaded scenarios There is often a need for synchronization. For example, in the case of producers and consumers, consumers need to wait for producers to generate data before they can consume.

A mutex alone does not solve the problem of synchronization: If the consumer acquires the lock first, but there is no resource available at this time, if the lock is occupied, the producer cannot acquire the lock, then it becomes a deadlock; if released immediately and re-entered, it will be polled and consume CPU resources.

A conditional variable (Condition Variable) is used in the Pthread library to block waiting for a condition, or to wake a thread that waits for the condition. Condition variable is represented by a variable of type pthread_cond_t, and its related functions are as follows:

#include <pthread.h>pthread_cond_t cond = PTHREAD_COND_INITIALIZER;int pthread_cond_destroy(pthread_cond_t *cond);int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);int pthread_cond_broadcast(pthread_cond_t *cond);int pthread_cond_signal(pthread_cond_t *cond);

As you can see from its wait function, Condtion is used with Mutext, and the basic flow is as follows:

消费者获取资源锁,如果当前无可用资源则调用cond_wait函数释放锁,并等待condtion通知。生产者产生资源后,获取资源锁,放置资源后嗲用cond_signal函数通知。并释放资源锁。消费者的cond_wait函数等到condtion通知后,重新获取资源锁,消费资源后再次释放资源锁。

As you can see, mutexes are used to protect resources, and wait functions are used to wait for signals, and the signal and broadcast functions are used to notify signals. Where the wait function has one release and re-fetch of the mutex, there is no deadlock between the producer and the consumer.

#include <stdlib.h> #include <pthread.h> #include <unistd.h> #include <queue> #include < Iostream>using namespace std;queue<int> buffer;pthread_cond_t has_product = Pthread_cond_initializer;        pthread_mutex_t lock = pthread_mutex_initializer;void* consumer (void *p) {while (true) {sleep (rand ()% 5);        Pthread_mutex_lock (&lock);        if (Buffer.empty ()) pthread_cond_wait (&has_product, &lock);        cout << "# # Consume" << Buffer.front () << Endl;        Buffer.pop ();    Pthread_mutex_unlock (&lock);        }}void* producer (void *p) {while (true) {sleep (rand ()% 5);        Pthread_mutex_lock (&lock);        Buffer.push (rand ()% 1000);        cout << ">>> Produce" << buffer.back () << Endl;        Pthread_cond_signal (&has_product);    Pthread_mutex_unlock (&lock);    }}int Main (int argc, char *argv[]) {pthread_t PID, CID; Srand (Time (NULL));    Pthread_create (&pid, NULL, producer, NULL);    Pthread_create (&cid, NULL, consumer, NULL);    Pthread_join (PID, NULL);    Pthread_join (CID, NULL); return 0;}
Signal Volume semaphore

The mutex variable is 0 or 1, which can be considered as the available quantity of a resource, and the mutex is 1 when initialized, indicating that there is an available resource, the resource is locking, the mutex is reduced to 0, the resource is no longer available, the resource is freed when unlocked, and the mutex is added to 1, indicating that there is another available resource.

Semaphores (Semaphore) are similar to mutexes, which indicate the number of available resources, unlike mutexes, which can be greater than 1. Its related operation functions are:

#include <semaphore.h>int sem_init(sem_t *sem, int pshared, unsigned int value);int sem_wait(sem_t *sem);int sem_trywait(sem_t *sem);int sem_post(sem_t * sem);int sem_destroy(sem_t * sem);

Here is a demonstration of the use of semaphores with examples of producers and consumers of a finite resource pool:

#include <stdlib.h> #include <pthread.h> #include <stdio.h> #include <unistd.h> #include <    semaphore.h> #define NUM 5int queue[num];sem_t blank_number, product_number;void *producer (void *arg) {int p = 0;        while (true) {sem_wait (&blank_number);        QUEUE[P] = rand ()% 1000 + 1;        printf (">>> produce%d\n", queue[p]);        Sem_post (&product_number);        p = (p+1)% NUM;    Sleep (rand ()%5);    }}void *consumer (void *arg) {int c = 0;        while (true) {sem_wait (&product_number);        printf ("# # Consume%d\n", queue[c]);        Queue[c] = 0;        Sem_post (&blank_number);        c = (c+1)% NUM;    Sleep (rand ()% 5);    }}int Main (int argc, char *argv[]) {pthread_t PID, CID;    Sem_init (&blank_number, 0, NUM);    Sem_init (&product_number, 0, 0);    Pthread_create (&pid, NULL, producer, NULL);    Pthread_create (&cid, NULL, consumer, NULL);    Pthread_join (PID, NULL); PtHread_join (CID, NULL);    Sem_destroy (&blank_number);    Sem_destroy (&product_number); return 0;}
Read/write Lock (Reader-writer lock)

A read-write lock is also a mutually exclusive operation between threads, but unlike a mutex, it is divided into two modes: Read and write, where the write pattern is the exclusive resource (as with the mutex), while the read mode is the shared resource, allowing multiple readers to improve concurrency.

Since the moment can not find a suitable small example to introduce it, and read-write lock model is relatively easy to understand, here is not an example.



From for notes (Wiz)

Linux advanced Programming--09. Thread Mutex and synchronization

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.