当前位置: 首页 > news >正文

Linux应用开发-16-POSIX 互斥锁

信号量也可以实现互斥访问临界资源,区别如下:

特性sem_t (作为二元信号量)pthread_mutex_t (专用互斥锁)
核心功能计数器 (0 和 1)锁 (Locked / Unlocked)
归属权无 (任何线程都能 post)有 (必须是上锁的线程才能解锁)
递归上锁导致死锁支持 (使用 RECURSIVE 类型)
错误检查无 (直接死锁)支持 (使用 ERRORCHECK 类型)
主要用途进程/线程间同步 (发信号)线程间互斥 (保护临界区)
效率,通用相对较重,专用通常更轻量、更快

先说明互斥锁的使用

锁的两种方式:静态初始化和动态初始化
静态初始化

pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;//默认的互斥锁
pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;//递归互斥锁
pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;//检错互斥锁
/*
默认的互斥锁,即快速互斥锁。互斥锁被线程 1 持有时,此时互斥锁处于闭锁状态,当线程 2 尝试获取互斥锁,那么线程 2 将会阻塞直至持有互斥锁的线程 1 解锁为止。
递归互斥锁。互斥锁被线程 1 持有时,线程 2 尝试获取互斥锁,将无法获取成功,并且阻塞等待,而如果是线程 1 尝试再次获取
互斥锁时,将获取成功,并且持有互斥锁的次数加 1。检错互斥锁。这是快速互斥锁的非阻塞版本,它会立即返回一个错误代码。
*/

动态初始化

//互斥锁初始化,pthread_mutexattr_t=NULL为默认互斥锁,否则用pthread_mutexattr_t attr互斥锁属性去设置
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t*mutexattr);
//阻塞等待互斥锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
//非阻塞,直接返回错误
int pthread_mutex_trylock(pthread_mutex_t *mutex);
//释放互斥锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
//销毁互斥锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);

以下说明互斥锁的信号量使用的差别

互斥锁信号量的基本用法:

//互斥锁 (pthread_mutex_t)
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);// 初始化
pthread_mutex_lock(&mutex);// 上锁
//=====临界区======
pthread_mutex_unlock(&mutex);// 解锁
pthread_mutex_destroy(&mutex);// 销毁//二元信号量 (sem_t)
sem_t sem;
sem_init(&sem, 0, 1);// 初始化 (初始值为 1)
sem_wait(&sem);// P操作 (减1, 变0)
//=====临界区======
sem_post(&sem);// V操作 (加1, 变1)
sem_destroy(&sem);// 销毁

互斥锁 (Mutex) —— 严格的“归属权”(解锁失败)

演示互斥锁有归属权。[main] 线程上锁,[thief_thread] 尝试解锁,操作会失败。

互斥锁的测试 (失败)

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>   
#include <string.h>// 静态初始化一个标准互斥锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;void* thief_thread(void* arg) {sleep(1); // 等待主线程先锁上printf("[thief_thread]: 我尝试解开 [main] 线程的锁...\n");// 本线程尝试解锁一个由“主线程”持有的锁int ret = pthread_mutex_unlock(&mutex);if (ret != 0) {// 在标准的 Linux Pthreads 实现中, 这会失败并返回 EPERMprintf("[thief_thread]: 解锁失败!错误: %s。(互斥锁有归属权)\n", strerror(ret));} else {printf("[thief_thread]: 解锁成功了。\n");}return NULL;
}int main() {// [main] 线程上锁pthread_mutex_lock(&mutex);printf("[main]: 我上锁了。\n");pthread_t tid;// [main] 线程创建了 [thief_thread] 线程pthread_create(&tid, NULL, thief_thread, NULL);// 等待 [thief_thread] 线程结束回收pthread_join(tid, NULL);printf("[main]: 我现在自己解锁。\n");pthread_mutex_unlock(&mutex); // [main] 线程自己正常解锁pthread_mutex_destroy(&mutex);printf("[main]: 程序结束。\n");return 0;
}
/*
[main]: 我上锁了。
[thief_thread]: 我尝试解开 [main] 线程的锁...
[thief_thread]: 解锁失败!错误: Operation not permitted。(互斥锁有归属权)
[main]: 我现在自己解锁。
[main]: 程序结束。
*/

信号量 (Semaphore) —— “同步”功能(解锁成功)

演示信号量没有归属权。[notifier_thread] 可以 sem_post(V操作),而 [main] 线程可以 sem_wait(P操作)。

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h> 
#include <unistd.h> sem_t sem; // 全局信号量void* notifier_thread(void* arg) {sleep(1); // 模拟一些工作printf("[notifier_thread]: 我工作完成了,给信号量 +1 (sem_post)...\n");// 信号量没有归属权,任何线程都可以 V 操作sem_post(&sem);printf("[notifier_thread]: 操作成功!我退出了。\n");return NULL;
}int main() {// 初始值为 0,“资源未就绪”sem_init(&sem, 0, 0); pthread_t tid;// [main] 线程创建了 [notifier_thread] 线程pthread_create(&tid, NULL, notifier_thread, NULL);printf("[main]: 我在等待信号量 (sem_wait),等待 [notifier_thread]...\n");// [main] 线程阻塞在这里,等待别人给它发信号sem_wait(&sem);printf("[main]: 我收到信号了![main] 线程继续运行。\n");pthread_join(tid, NULL); // 等待子线程结束sem_destroy(&sem); // 清理信号量printf("[main]: 程序结束。\n");return 0;
}
/*
[main]: 我在等待信号量 (sem_wait),等待 [notifier_thread]...
[notifier_thread]: 我工作完成了,给信号量 +1 (sem_post)...
[notifier_thread]: 操作成功!我退出了。
[main]: 我收到信号了![main] 线程继续运行。
[main]: 程序结束。
*/

信号量 (Semaphore) —— 尝试“递归”加锁(导致死锁)

sem_t(初始值为1)不能被同一个线程连续wait两次,否则会立即死锁。

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>int main() {sem_t sem;// 初始化为 1 (作为互斥锁)sem_init(&sem, 0, 1);printf("[main]: 正在尝试第一次 sem_wait()...\n");sem_wait(&sem); // 第 1 次:成功,信号量值变为 0printf("[main]: 第一次 sem_wait() 成功!\n");printf("[main]: 正在尝试第二次 sem_wait()...\n");// 信号量值现在是 0,[main] 线程再次调用 sem_wait()// [main] 线程自己把自己“锁死”了sem_wait(&sem); // 这一行永远不会被执行printf("[main]: 这一行永远不会打印!\n"); sem_post(&sem);sem_destroy(&sem);return 0;
}
/*
[main]: GnuPG: 正在尝试第一次 sem_wait()...
[main]: 第一次 sem_wait() 成功!
[main]: 正在尝试第二次 sem_wait()...
(程序在此处永久挂起,光标卡住不动,直到您按 Ctrl+C 强制终止)
*/

递归互斥锁 (Recursive Mutex) —— “递归”加锁(成功)

pthread_mutex_t(互斥锁)通过设置递归属性,可以安全地被同一个线程连续加锁两次,而不会死锁。

#include <stdio.h>
#include <pthread.h>int main() {pthread_mutex_t mutex;pthread_mutexattr_t attr; // 互斥锁属性// 1. 初始化属性pthread_mutexattr_init(&attr);// 2. 将属性设置为“递归锁”pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);// 3. 使用这个属性初始化锁pthread_mutex_init(&mutex, &attr);// 4. 销毁属性对象 (锁已创建,不再需要)pthread_mutexattr_destroy(&attr);// 5. 开始测试printf("[main]: 正在尝试第一次 lock()...\n");pthread_mutex_lock(&mutex); // 第 1 次:成功,锁计数器 = 1printf("[main]: 第一次 lock() 成功!\n");printf("[main]: 正在尝试第二次 lock()...\n");// 【成功】// 因为这是“递归锁”,内核检查到是同一个线程在加锁// 它不会阻塞,只会将内部计数器增加到 2pthread_mutex_lock(&mutex); printf("[main]: 第二次 lock() 也成功了!(没有死锁)\n");// 必须解锁相同次数printf("[main]: 正在解锁第一次...\n");pthread_mutex_unlock(&mutex); // 计数器减为 1printf("[main]: 正在解锁第二次...\n");pthread_mutex_unlock(&mutex); // 计数器减为 0,锁被真正释放// 6. 销毁锁pthread_mutex_destroy(&mutex);printf("[main]: 程序正常结束。\n");return 0;
}
/*
[main]: 正在尝试第一次 lock()...
[main]: 第一次 lock() 成功!
[main]: 正在尝试第二次 lock()...
[main]: 第二次 lock() 也成功了!(没有死锁)
[main]: GnuPG: 正在解锁第一次...
[main]: 正在解锁第二次...
[main]: 程序正常结束。
*/
http://www.dtcms.com/a/586949.html

相关文章:

  • 做区块链网站需要注意哪些app软件定制开发一般多少钱
  • php网站制作 青岛长沙seo网站优化
  • 太原加盟网站制作codex wordpress
  • 黑河商城网站建设洛阳网站建设优化案例
  • 成都公司网站开发新媒体营销课程心得体会
  • 外贸网站推广中山摄影网站建设内容
  • 快手作品推广网站资源共享网站怎么做
  • 【操作系统】第三章 计算机体系结构及内存分层体系
  • 区块链交易网站建设wordpress foundation
  • 网站中文域名到期有没有影响传智播客黑马程序员
  • 基于 Object 类及包装类的专项实验
  • 洛阳400电话洛阳网站seo公司网站SEO优化哪个做得好
  • 深入理解 CGLIB 代理技术:原理、使用与实战
  • 做网站网站的虚拟空间北滘网站开发
  • 教育培训网站模板摄影网站设计论文
  • 东莞seo建站优化收费网页设计导航字体大小
  • 控制面板网站iis7搭建网站织梦
  • 前端和网站部署做网站的wordpress 导航条
  • 蓟州网站建设可以做编程题的网站
  • 网站开发价格明细湖南seo服务电话
  • 深圳网站建设服务哪便宜那些视频网站能用来直接做href
  • 建设网站需要机房吗昆明旅游网页设计
  • 网站开发 印花税开发一个网站需要多少时间
  • 服务器IP做网址打开网站百度seo优化价格
  • php自己做网站吗建个人网站的详细步骤
  • 网站风格分析怎么写类似猪八戒的网站建设
  • 【开题答辩全过程】以 高考智能填报系统为例,包含答辩的问题和答案
  • 苏州网站建设与网络推广简述网站推广的意义和方法
  • 手机版网站开发工具做模板网站怎么放视频教程
  • 网站建设php培训ui做自适应网站