互斥锁的作用
保护共享数据: 在并发机制的情况下,有时候会有多个线程同时访问同一片数据,为了保护数据操作的准确性就需要通过加锁来进行保护。
保持操作互斥: 可能一个程序会有多个操作,但是同一个时间只能有一个操作被执行,例如a/b两个操作,如果a被执行,b就不能被执行,同理b被执行,a就不能执行
操作函数
pthread_mutex_t lock; /* 互斥锁定义 */ pthread_mutex_init(&lock, NULL); /* 动态初始化, 成功返回0,失败返回非0 */ pthread_mutex_t thread_mutex = PTHREAD_MUTEX_INITIALIZER; /* 静态初始化 */ pthread_mutex_lock(&lock); /* 阻塞的锁定互斥锁 */ pthread_mutex_trylock(&thread_mutex);/* 非阻塞的锁定互斥锁,成功获得互斥锁返回0,如果未能获得互斥锁,立即返回一个错误码 */ pthread_mutex_unlock(&lock); /* 解锁互斥锁 */ pthread_mutex_destroy(&lock) /* 销毁互斥锁 */
实例:保护共享数据
第一个作用是保护共享的数据,在说明之前先看一下没有互斥锁保护的情况下,会发生什么样的状况,例子如下:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <pthread.h> static int g_count = 0; static void *thread_fun_1(void *data) { g_count++; printf("%s g_count: %d\n", __func__, g_count); } static void *thread_fun_2(void *data) { g_count++; printf("%s g_count: %d\n", __func__, g_count); } static void *thread_fun_3(void *data) { g_count++; printf("%s g_count: %d\n", __func__, g_count); } int main(int argc, char const *argv[]) { pthread_t pid[3]; pthread_create(&pid[0], NULL, thread_fun_1, NULL); pthread_create(&pid[1], NULL, thread_fun_2, NULL); pthread_create(&pid[2], NULL, thread_fun_3, NULL); pthread_join(pid[0], NULL); pthread_join(pid[1], NULL); pthread_join(pid[2], NULL); return 0; }
3个线程都会对g_count进行操作,没有任何保护的情况下,3个线程是存在竞争关系的,所以g_count最终可能会是1、2、3三种值中的一种,运行结果如下
下面开始对数据进行保护,例子如下:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <pthread.h> static pthread_mutex_t g_mutex_lock; static int g_count = 0; static void *thread_fun_1(void *data) { pthread_mutex_lock(&g_mutex_lock); g_count++; printf("%s g_count: %d\n", __func__, g_count); pthread_mutex_unlock(&g_mutex_lock); } static void *thread_fun_2(void *data) { pthread_mutex_lock(&g_mutex_lock); g_count++; printf("%s g_count: %d\n", __func__, g_count); pthread_mutex_unlock(&g_mutex_lock); } static void *thread_fun_3(void *data) { pthread_mutex_lock(&g_mutex_lock); g_count++; printf("%s g_count: %d\n", __func__, g_count); pthread_mutex_unlock(&g_mutex_lock); } int main(int argc, char const *argv[]) { int ret; pthread_t pid[3]; ret = pthread_mutex_init(&g_mutex_lock, NULL); if (ret != 0) { printf("mutex init failed\n"); return -1; } pthread_create(&pid[0], NULL, thread_fun_1, NULL); pthread_create(&pid[1], NULL, thread_fun_2, NULL); pthread_create(&pid[2], NULL, thread_fun_3, NULL); pthread_join(pid[0], NULL); pthread_join(pid[1], NULL); pthread_join(pid[2], NULL); pthread_mutex_destroy(&g_mutex_lock); return 0; }
对数据g_count的操作进行加锁之后,同一个时间只有一个线程能获取到锁,也就是只有一个线程能对g_count进行操作,保证了g_count的数据的准确性
实例:保持操作的互斥性
有些情况下,2个不同的操作是不能同时进行的,例如fingerprint中的enroll和verify同一时间只能有一个操作进行。保持操作的互斥性本质上其实还是在保护共有的数据。看下下面的例子,打印hello的时候,world是无法打印的,如果希望打印world只能等待打印hello的线程退出之后再打印
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <pthread.h> static pthread_mutex_t g_mutex_lock; static void *thread_fun_1(void *data) { pthread_mutex_lock(&g_mutex_lock); int i = 0; while (i < 10) { printf("hello\n"); i++; sleep(1); } pthread_mutex_unlock(&g_mutex_lock); } static void *thread_fun_2(void *data) { pthread_mutex_lock(&g_mutex_lock); int i = 0; while (i < 10) { printf("world\n"); i++; sleep(1); } pthread_mutex_unlock(&g_mutex_lock); } static void do_print_hello() { pthread_t pth_id; int result = pthread_create(&pth_id, NULL, thread_fun_1, NULL); } static void do_print_world() { pthread_t pth_id; int result = pthread_create(&pth_id, NULL, thread_fun_2, NULL); } int main(int argc, char const *argv[]) { int ret; int cid; ret = pthread_mutex_init(&g_mutex_lock, NULL); if (ret != 0) { printf("mutex init failed\n"); return -1; } while (1) { scanf("%d", &cid); getchar(); switch (cid) { case 0: do_print_hello(); break; case 1: do_print_world(); break; default: break; } } pthread_mutex_destroy(&g_mutex_lock); return 0; }
上面的互斥锁是阻塞式的锁,也可以通过非阻塞式的锁进行,看下面的例子,pthread_mutex_trylock()函数如果获取到互斥锁了,会返回0,如果没有获取的互斥锁,会立即返回一个非0值,例子中通过g_cancel来通知线程进行退出,如果当前正在打印hello,发出打印world命令之后,通过pthread_mutex_trylock()就能知道当前有没有打印线程正在运行,如果有在运行的线程,通过置位g_cancel来退出正在运行的线程
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <pthread.h> static pthread_mutex_t g_mutex_lock; static int g_cancel = 0; static void *thread_fun_1(void *data) { if (pthread_mutex_trylock(&g_mutex_lock) != 0) { g_cancel = 1; return 0; } int i = 0; g_cancel = 0; while (i < 10) { if (g_cancel) break; printf("hello\n"); i++; sleep(1); } pthread_mutex_unlock(&g_mutex_lock); } static void *thread_fun_2(void *data) { if (pthread_mutex_trylock(&g_mutex_lock) != 0) { g_cancel = 1; return 0; } int i = 0; g_cancel = 0; while (i < 10) { if (g_cancel) break; printf("world\n"); i++; sleep(1); } pthread_mutex_unlock(&g_mutex_lock); } static void do_print_hello() { pthread_t pth_id; int result = pthread_create(&pth_id, NULL, thread_fun_1, NULL); } static void do_print_world() { pthread_t pth_id; int result = pthread_create(&pth_id, NULL, thread_fun_2, NULL); } int main(int argc, char const *argv[]) { int ret; int cid; ret = pthread_mutex_init(&g_mutex_lock, NULL); if (ret != 0) { printf("mutex init failed\n"); return -1; } while (1) { scanf("%d", &cid); getchar(); switch (cid) { case 0: do_print_hello(); break; case 1: do_print_world(); break; default: break; } } pthread_mutex_destroy(&g_mutex_lock); return 0; }
原文链接:https://blog.csdn.net/qq_33242956/article/details/91861208