线程同步方式---1 互斥锁
概述:
互斥锁可能是最简单的锁机制了。也是一个阻塞锁。
函数API:
1.1:用宏常量初始化:
1 pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
1.2:用函数初始化:
1 #include <pthread.h> 2 3 int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
2.设置互斥量属性
1 #include <pthread.h> 2 3 int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
attr:互斥量的属性结构指针
type:PTHREAD_MUTEX_NORMAL(默认属性),PTHREAD_MUTEX_ERRORCHECK(会进行错误检查,速度比较慢),PTHREAD_MUTEX_RECURSIVE(递归锁)。对于递归锁,同一个线程对一个递归锁加锁多次,会有一个锁计数器,解锁的时候也需要解锁这个次数才能释放该互斥量。
3.加锁与解锁
1 #include <pthread.h> 2 3 int pthread_mutex_lock(pthread_mutex_t *mutex); 4 int pthread_mutex_trylock(pthread_mutex_t *mutex); 5 int pthread_mutex_unlock(pthread_mutex_t *mutex);
参数都是互斥量指针。pthread_mutex_lock()得不到锁会阻塞,int pthread_mutex_trylock()得不到锁会立即返回,并返回EBUSY错误。
还有一个pthread_mutex_timedlock()会根据时间来等待加锁,如果这段时间得不到锁会返回ETIMEDOUT错误!
1 #include <pthread.h> 2 #include <time.h> 3 4 int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict abs_timeout);
4.销毁互斥量
1 #include <pthread.h> 2 3 int pthread_mutex_destroy(pthread_mutex_t *mutex);
mutex:创建的互斥量指针
三.简单例子
写个简单的例子,主线程消费,子线程生产,并模拟使用过程中可能遇到的缺点
1 /** 2 * @file pthread_mutex.c 3 */ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <unistd.h> 9 #include <pthread.h> 10 11 /* 定义互斥量 */ 12 pthread_mutex_t mtx; 13 /* 互斥量属性 */ 14 pthread_mutexattr_t mtx_attr; 15 /* 全局资源 */ 16 int money; 17 18 void err_exit(const char *err_msg) 19 { 20 printf("error:%s\n", err_msg); 21 exit(1); 22 } 23 24 /* 线程函数 */ 25 void *thread_fun(void *arg) 26 { 27 while (1) 28 { 29 /* 加锁 */ 30 pthread_mutex_lock(&mtx); 31 32 printf("子线程进入临界区查看money\n"); 33 if (money == 0) 34 { 35 money += 200; 36 printf("子线程:money = %d\n", money); 37 } 38 39 /* 解锁 */ 40 pthread_mutex_unlock(&mtx); 41 42 sleep(1); 43 } 44 45 return NULL; 46 } 47 48 int main(void) 49 { 50 pthread_t tid; 51 52 /* 初始化互斥量属性 */ 53 if (pthread_mutexattr_init(&mtx_attr) == -1) 54 err_exit("pthread_mutexattr_init()"); 55 56 /* 设置互斥量属性 */ 57 if (pthread_mutexattr_settype(&mtx_attr, PTHREAD_MUTEX_NORMAL) == -1) 58 err_exit("pthread_mutexattr_settype()"); 59 60 /* 初始化互斥量 */ 61 if (pthread_mutex_init(&mtx, &mtx_attr) == -1) 62 err_exit("pthread_mutex_init()"); 63 64 /* 创建一个线程 */ 65 if (pthread_create(&tid, NULL, thread_fun, NULL)== -1) 66 err_exit("pthread_create()"); 67 68 money = 1000; 69 while (1) 70 { 71 /* 加锁 */ 72 pthread_mutex_lock(&mtx); 73 74 if (money > 0) 75 { 76 money -= 100; 77 printf("主线程:money = %d\n", money); 78 } 79 80 /* 解锁 */ 81 pthread_mutex_unlock(&mtx); 82 83 sleep(1); 84 } 85 86 return 0; 87 }
主线程和子线程都对money的操作进行了互斥量保护。68行,初始化money是1000,主线程每次消耗100,子线程只有到money是0是才会生产。sleep(1)防止独占cpu,也方便打印信息。编译运行:
可以看到这里有个非常浪费资源的问题:主线程消耗money的时候,子线程它不知道什么时候才消耗完,每次内核调度到它时,它都进入临界区加锁互斥量,然后查看money,再解锁。这无意义的操作,简直是极大的浪费!有什么办法可以解决这个问题呢?它有一个好伙伴,叫条件变量。
四.死锁
假设:当线程1获取锁1,再获取锁2后才能进入临界区1,线程2获取锁2,再获取锁1才能进入临界区2。某个时刻,线程1获取了锁1,再去获取锁2的时候发现锁2已经被线程2锁住了,而线程2获取锁2后,发现锁1被线程1锁住了。这样2个线程谁也不让谁,都进不了自己的临界区,就产生了死锁现象!一般遇到这种情况常见的解决办法是:规定统一的加锁顺序。线程1和线程2都按照先锁1,再锁2。还一种就是使用pthread_mutex_trylock(),如果该函数返回EBUSY错误,就释放这个线程的所有锁,不过效率有点低。
转自:http://www.cnblogs.com/yuuyuu/p/5143881.html