Thread synchronization and mutex

Posted by scross on Mon, 29 Nov 2021 00:54:03 +0100

The concept of thread synchronization

Thread synchronization means that 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 this function to ensure data consistency.

  Examples of thread synchronization

Create two threads, let the two threads share a global variable int number, and then let each thread count 5000 times. See what the number value is printed out at last?

Thread A code snippet:

Thread B snippet:

 

 

Code snippet Description:

The purpose of calling usleep in the code is to enable two sub threads to use the CPU in turn, so as to avoid a sub thread completing 5000 times in a time slice. Perform + + operation on number and use the intermediate variable cur to simulate the situation that the CPU runs out of time slices and gives up the CPU as much as possible.

 

Test results: after many tests, the final results show that the number value may be less than 5000 * 2 = 10000.

Analysis reason:

         If child thread A finishes executing cur + + operation and has not assigned the value of cur to number, it loses the execution right of cpu, child thread B gets the execution right of cpu, and child thread B finally executes number=cur, and then loses the execution right of cpu; At this time, sub thread A obtains the execution right of the cpu again and executes the operation number=cur. In this way, the value of number just written back by thread B will be overwritten, resulting in the number value not meeting the expected value.

How to solve this problem:

          Linux provides a mutex (also known as mutex). Each thread attempts to lock the resource before operating. The operation can only be performed after locking successfully. The operation is unlocked after the operation is completed.

         Resources are still shared and threads compete, but the access to resources will become mutually exclusive through "lock", and then time-related errors will not occur again.

 

         When thread 1 accesses shared resources, it must first judge whether the lock is locked. If it is locked, it will block the waiting; If the lock is unlocked, lock the lock. At this time, you can access the shared resources. After the access is completed, release the lock, so that other threads have a chance to obtain the lock.

         It should be noted that only one thread can hold the lock at the same time in the figure. As long as the thread does not complete the operation, the lock will not be released. After using mutex, the two threads changed from parallel operation to serial operation, which reduced the efficiency, but the problem of inconsistent data was solved.

Mutex main correlation function

pthread_mutex_t mutex; Define mutex

pthread_ mutex_ init(&mutex, NULL); Mutex initialization  

pthread_ mutex_ lock(&mutex); Lock

pthread_ mutex_ unlock(&mutex); Unlock

pthread_ mutex_ destroy(&mutex); Destroy mutex
 

#include <stdio.h>
#include<iostream>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
using namespace std;

#define NUM 20000
int number = 0;

//Define a lock
pthread_mutex_t mutex;

void *mythread1(void *args)
{
        int i = 0;
        int n;
        for (i = 0; i < NUM; i++)
        {
                //Lock
                pthread_mutex_lock(&mutex);
                n = number;
                n++;
                number = n;
                cout << "[" << n << "]" << endl;
                //Unlock
                pthread_mutex_unlock(&mutex);
        }



}


void *mythread2(void *args)
{
        int i = 0;
        int n;
        for (i = 0; i < NUM; i++)
        {
                //Lock
                pthread_mutex_lock(&mutex);
                n = number;
                n++;
                number = n;
                cout << "[" << n << "]" << endl;
                //Unlock
                pthread_mutex_unlock(&mutex);
        }

}

int main()
{
        int ret;
        pthread_t thread1;
        pthread_t thread2;


        //Mutex initialization
        pthread_mutex_init(&mutex, NULL);

        ret = pthread_create(&thread1, NULL, mythread1, NULL);
        if(ret!=0)
        {
                cout << "pthread_create error, " << strerror(ret) << endl;
                return -1;
        }

        ret = pthread_create(&thread2, NULL, mythread2, NULL);
        if(ret!=0)
        {
                cout << "pthread_create error, " << strerror(ret) << endl;
                return -1;
        }

        //Wait for the thread to end
        pthread_join(thread1, NULL);
        pthread_join(thread2, NULL);

        //Release mutex
        pthread_mutex_destroy(&mutex);
        return 0;
}

  After running the code several times, the result is still 40000. The successful use of mutex eliminates the problem of thread synchronization.

 

 

 

 

 

 

Topics: Linux Operation & Maintenance server