This article introduces the thread synchronization and mutex mechanism under Linux - mutex lock. When multiple threads are concurrent, multiple consumers will get data. In this case, the data needs to be protected. For example, like the train ticket system and the bus ticket system, the total number of tickets is fixed, but there are many ticket buying terminals.
Mutex is used to protect a resource from being used by two or more threads at the same time.
Why lock it?
This is because multiple threads share the resources of the process. When you want to access the public interval (global variable), when a thread accesses it, you need to lock it to prevent other threads from accessing it, so as to realize the exclusive use of resources. Only one thread can master a mutex at a time, and only threads with locked status can operate on shared resources. If another thread wants to lock a locked mutex, the thread will hang until the locked thread releases the mutex.
1. Introduction to mutex
In programming, the concept of object mutex is introduced to ensure the integrity of shared data operation. Each object corresponds to a tag called "mutex", which is used to ensure that only one thread can access the object at any time.
A set of mutex functions specially used for thread mutual exclusion is defined under Linux system.
Mutex is a simple locking method to control access to shared resources. This mutex has only two states (lock and unlock). Mutex can be regarded as a global variable in a sense.
Conclusion: mutex can protect a resource and can only be used by one thread at the same time.
2. Mutex related functions
#include <pthread.h> //Destroy mutex int pthread_mutex_destroy(pthread_mutex_t *mutex); //Initialize mutex int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr); //Locking: blocking mode int pthread_mutex_lock(pthread_mutex_t *mutex); //Locking: non blocking mode int pthread_mutex_trylock(pthread_mutex_t *mutex); //Unlock int pthread_mutex_unlock(pthread_mutex_t *mutex); explain: about Linux Semaphore under/Compile the read-write lock file,It needs to be specified in the compilation options-D_GNU_SOURCE Otherwise use gcc Compilation will appear PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP Undeclared(First use in this function) Such tips. for example: $ gcc app.c -lpthread -D_GNU_SOURCE
2.1 initialize mutex
Header file #include <pthread.h> Define function int pthread_mutex_init( pthread_mutex_t *mutex, const pthread_mutex_attr_t* attr ); Function description This function initializes a mutex variable if the parameter attr by NULL,Mutex variable mutex Use default properties.
2.2 destroy mutex
Header file #include <pthread.h> Define function int pthread_mutex_destroy ( pthread_mutex_t *mutex ); Function description This function is used to release the assigned parameters mutex Resources. Return value The return value is 0 when the call is successful, otherwise a non-0 error code is returned.
2.3 locking
Header file #include <pthread.h> Define function int pthread_mutex_lock( pthread_mutex_t *mutex ); Function description This function is used to lock mutex variables. If parameter mutex If the mutex is locked, the calling thread will be blocked until other threads pair mutex Unlock. If the lock is successful, 0 will be returned.
2.4 attempt to lock - non blocking
Header file #include <pthread.h> Define function int pthread_mutex_trylock( pthread_t *mutex ); Function description This function is used to lock mutex The specified mutex, but not blocking. Return value If the mutex is locked, the call does not block the wait, but returns an error code. If the lock is successful, 0 will be returned.
2.5 unlocking
Header file #include <pthread.h> Define function int pthread_mutex_unlock( pthread_mutex_t *mutex ); Function description This function is used to unlock a mutex. If the current thread has parameters mutex The specified mutex. This call unlocks the mutex. If the unlocking is successful, 0 will be returned. explain: Multiple unlocking of the same lock has no superposition effect. If the lock is locked, multiple unlocking is only effective once.
3. Application model of mutex framework
pthread_mutex_t mutex; void Thread 1(void) { while(1) { //Lock pthread_mutex_lock(&mutex); .....Body code...... //Unlock pthread_mutex_unlock(&mutex); } } void Thread 2(void) { while(1) { //Lock pthread_mutex_lock(&mutex); .....Body code...... //Unlock pthread_mutex_unlock(&mutex); } } int main(void) { //Initialize mutex pthread_mutex_init(&mutex,NULL); .....Body code...... //Destroy mutex pthread_mutex_destroy(&mutex); }
4. Case code: lock protection for public functions
The following code is that two threads call a print function at the same time to print: "123" and "456" respectively.
void print(char *p) { while(*p!='\0') { printf("%c",*p++); sleep(1); } } void *thread1_func(void *arg) { print("123\n"); } void *thread2_func(void *arg) { print("456\n"); }
If not protected, the default print result is:
[wbyq@wbyq linux-share-dir]$ ./a.out 412536
The expected result should be that 123 \ 456 are printed continuously. In this case, it can be locked for protection.
Example code for locking:
#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <dirent.h> #include <stdlib.h> #include <pthread.h> pthread_mutex_t mutex; void print(char *p) { while(*p!='\0') { printf("%c",*p++); sleep(1); } } /* Thread worker function */ void *thread_work_func(void *dev) { while(1) { //Lock pthread_mutex_lock(&mutex); print("123\n"); //Unlock pthread_mutex_unlock(&mutex); usleep(1000*10); } } /* Thread worker function */ void *thread_work_func2(void *dev) { //Lock pthread_mutex_lock(&mutex); print("456\n"); //Unlock pthread_mutex_unlock(&mutex); usleep(1000*10); } int main(int argc,char **argv) { //Initialize mutex pthread_mutex_init(&mutex,NULL); /*1. Create child thread 1*/ pthread_t thread_id; if(pthread_create(&thread_id,NULL,thread_work_func,NULL)!=0) { printf("Child thread 1 creation failed.\n"); return -1; } /*2. Create child thread 2*/ pthread_t thread_id2; if(pthread_create(&thread_id2,NULL,thread_work_func2,NULL)!=0) { printf("Child thread 2 creation failed.\n"); return -1; } /*3. Introduction to waiting thread*/ pthread_join(thread_id,NULL); pthread_join(thread_id2,NULL); //Destroy mutex pthread_mutex_destroy(&mutex); return 0; }
5. Case code: simulate the train ticket sales system (protect the same global variable)
The following code simulates a train ticket sales system. If it is not locked here, negative tickets may be sold.
#include <stdio.h> #include <pthread.h> int cnt = 121; //Train tickets, public resources (global) void* pthread1(void* args) { while(ticketcount > 0) { printf("window A Start selling tickets,Tickets are:%d\n",cnt); sleep(2); cnt--; printf("window A End of ticket sales,The last ticket is:%d\n",cnt); } } void* pthread2(void* args) { while(cnt > 0) { printf("window B Start selling tickets,The ticket is:%d\n",cnt); sleep(2); cnt--; printf("window B End of ticket sales,The last ticket is:%d\n",cnt); } } int main() { pthread_t pthid1 = 0; pthread_t pthid2 = 0; pthread_create(&pthid1,NULL,pthread1,NULL); pthread_create(&pthid2,NULL,pthread2,NULL); pthread_join(pthid1,NULL); pthread_join(pthid2,NULL); return 0; }
Train ticketing system after locking
#include <stdio.h> #include <pthread.h> int cnt = 121; pthread_mutex_t lock; void* pthread1(void* args) { while(1) { pthread_mutex_lock(&lock); //Because you want to access the global shared variables, you need to lock them if(cnt > 0) //If there are tickets { printf("window A Start selling tickets,The ticket is:%d\n",cnt); sleep(2); cnt--; printf("window A End of ticket sales,The last ticket is:%d\n",cnt); } else { pthread_mutex_unlock(&lock); pthread_exit(NULL); } pthread_mutex_unlock(&lock); sleep(1); //Put it outside the lock so that the other has time to lock it } } void* pthread2(void* args) { while(1) { pthread_mutex_lock(&lock); if(cnt>0) { printf("window B Start selling tickets--The ticket is:%d\n",cnt); sleep(2); cnt--; printf("window B End of ticket sales,The last ticket is:%d\n",cnt); } else { pthread_mutex_unlock(&lock); pthread_exit(NULL); } pthread_mutex_unlock(&lock); sleep(1); } } int main() { pthread_t pthid1 = 0; pthread_t pthid2 = 0; //Initialization lock pthread_mutex_init(&lock,NULL); //Create thread pthread_create(&pthid1,NULL,pthread1,NULL); pthread_create(&pthid2,NULL,pthread2,NULL); //Wait for the thread to end pthread_join(pthid1,NULL); pthread_join(pthid2,NULL); //Destroy lock pthread_mutex_destroy(&lock); return 0; }