int pthread_mutex_unlock(pthread_mutex_t *mutex);功能: 对指定的互斥锁解锁参数: mutex:互斥锁地址返回值: 成功:0 失败:非0错误码
- 销毁互斥量
- 使用 PTHREAD_ MUTEX_ INITIALIZER 初始化的互斥量不需要销毁
- 不要销毁一个已经加锁的互斥量
- 已经销毁的互斥量,要确保后面不会有线程再尝试加锁
- 加锁的粒度要够小
#include <stdio.h>#include <pthread.h>#include <unistd.h>pthread_mutex_t mutex;// 创建锁变量//全局变量,所有线程共享int ticket = 10;void* get_tickets(void* arg){ long id = (long)arg; while (1){usleep(1000);// 加锁pthread_mutex_lock(&mutex);if (ticket > 0){// 有票--ticket;printf("线程%ld获得一张票,剩余%d张票\n",id,ticket);// 解锁pthread_mutex_unlock(&mutex);}else{// 无票,退出// 解锁pthread_mutex_unlock(&mutex);break;} }}int main(){ pthread_t t[5]; // 初始化锁 pthread_mutex_init(&mutex, NULL); // 创建5个线程 long i = 0; for (; i < 5; ++i) { pthread_create(t+i, NULL, get_tickets, (void*)(i+1)); } // 释放5个线程 for (i = 0; i < 5; ++i) {pthread_join(t[i], NULL); } // 销毁锁 pthread_mutex_destroy(&mutex); return 0;}运行结果如下:

文章插图
总结几点并回答几个问题:
锁的作用: 对临界区进行保护,所有的执行流线程都必须遵守这个规则:lock——>访问临界区——>unlock
需要注意的点:
- 所有的线程必须看到同一把锁,锁本身就是临界资源,所以锁本身需要先保证自身安全申请锁的过程不能出现中间态,必须保证原子性
- 任一线程持有锁之后,其它线程如果还想申请锁时申请不到的,保证互斥性
进入等待队列进行等待,从运行队列转移到等待队列,状态由R变成S,持有锁的线程unlock之后,需要唤醒等待队列中的第一个线程
struct mutex{ int lock;// 0 1 // ... sturct wait_queue;//锁下的等待队列}互斥量的原理大多数体系结构都提供了swap或exchange指令,该指令的作用是把寄存器和内存单元的数据相交换,由于只有一条指令,保证了原子性,即使是多处理器平台,访问内存的总线周期也有先后,一个处理器上的交换指令执行时另一个处理器的交换指令只能等待总线周期 。下面是lock和unlock的伪代码
lock: movb $0, %a1 # 把0值放进寄存器a1里 xchgb %a1, mutex # 交换a1寄存器的内容和锁的值(无线程使用锁时,metux的值为1) if (%a1 > 0)return 0; # 得到锁 else挂起等待; goto lock;unlock: movb $1 mutex #把1赋给锁 唤醒等待的线程; return 0;
经验总结扩展阅读
- 1500大卡相当于多少食物
- 为什么二手房越来越难卖
- 龙眼泡酒配方
- 香菇蒸多久能蒸熟
- 一条香烟不拆封能放多久
- 2023年农历七月十二适不适合结婚
- 2023年农历七月十六可不可以结婚农历二零二三年七月十六能不能结婚
- 2023年农历七月二十结婚会幸福吗
- 2023年农历七月二十一是不是结婚吉日 今天可以迎亲吗
- 2023年农历七月二十二结婚吉利吗 是黄道吉日吗