【线程同步】条件变量condition为什么必须配合互斥体mutex使用

news/2024/5/19 3:09:31 标签: condition, mutex, lock, 线程同步, 同步锁
lock" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">

前言

线程同步属于操作系统方面的知识,它不属于某个具体的语言,也不属于某个具体的库

所有支持线程的语言,都有类似的API,所以我把这篇博客既归到Java专栏,又归到C++专栏里

要研究的问题

  1. 为什么使用condition时,先要对mutex上锁
  2. 为什么等待condition时,会暂时释放mutex

原因分析

其实,这个问题并不难

之所以很多人觉得难,是因为没有真正搞清楚自己想要干什么,看到别人这么用,就想盲目拿来用

首先,互斥体mutex大家应该都很容易理解,就是给资源上锁,防止并发操作,导致程序异常

条件变量condition的作用,则是等待资源的某个具体状态发生时,再执行代码

那么,答案就很清楚了,因为状态是属于某个具体资源的,如果没有mutex的保证,状态判断可能也是错误的

举个栗子

比如说,mutex控制的资源是一个数组

A线程,要在数组为空时,去做一些事情,就会等待condition-a

B线程,要在数组数量大于100时,去做一些事情,就会等待condition-b

C线程,在对数组进行一波操作之后

判断a条件符合,则发出一个condition-a成立的信号,如果b条件符合,则发出一个condition-b成立的信号

这样,问题一就可以很好地解释了

至于问题二,如果等待condition时不释放mutex的话,那么其它线程永远无法改变资源的状态,条件永远也不可能成立

优点分析

使用condition的好处是,我们对资源的访问控制更加精细

我们只等待某个具体的状态,而不是资源一发生变化,就唤醒所有线程

这样不但会造成资源浪费,并且代码可读性也不强,线程被唤醒后,如果不符合条件还要重新退回等待状态

代码示例

简单以C语言SDL库为例,说明mutex和cond的使用格式,其它语言或框架大致类似


	#include <SDL.h>
	#include <stdio.h>
	
	SDL_mutex *mutex = NULL;
	SDL_cond *cond = NULL;
	
	int thread_work(void *arg) {
	
	  printf("Thread-2 Lock Mutex Start\n");
	  SDL_LockMutex(mutex);
	  printf("Thread-2 Lock Mutex Success\n");
	
	  printf("Thread-2 Working with Mutex\n");
	  sleep(4);
	
	  printf("Thread-2 Wait Condition Start\n");
	  SDL_CondWait(cond, mutex);
	  printf("Thread-2 Wait Condition Success\n");
	
	  printf("Thread-2 Unlock Mutex\n");
	  SDL_UnlockMutex(mutex);
	
	  printf("Thread-2 Finish\n");
	
	  return 0;
	}
	
	#undef main
	int main() {
	
	  mutex = SDL_CreateMutex();
	  cond = SDL_CreateCond();
	
	  SDL_Thread *t = SDL_CreateThread(thread_work, "Thread-2", NULL);
	
	  printf("Thread-1 Working\n");
	  sleep(2);
	
	  printf("Thread-1 Lock Mutex Start\n");
	  SDL_LockMutex(mutex);
	  printf("Thread-1 Lock Mutex Success\n");
	
	  printf("Thread-1 Working with Mutex\n");
	  sleep(2);
	
	  printf("Thread-1 Send Condition Signal\n");
	  SDL_CondSignal(cond);
	
	  printf("Thread-1 Working with Mutex\n");
	  sleep(2);
	
	  printf("Thread-1 Unlock Mutex\n");
	  SDL_UnlockMutex(mutex);
	
	  printf("Thread-1 Wait Thread-2 Finish Start\n");
	  SDL_WaitThread(t, NULL);
	  printf("Thread-1 Wait Thread-2 Finish Success\n");
	
	  printf("Thread-1 Destroy Mutex Start\n");
	  printf("Thread-1 Destroy Condition Start\n");
	  SDL_DestroyMutex(mutex);
	  SDL_DestroyCond(cond);
	  printf("Thread-1 Destroy Mutex Success\n");
	  printf("Thread-1 Destroy Condition Success\n");
	
	  return 0;
	}


http://www.niftyadmin.cn/n/2470.html

相关文章

JZ2440驱动

第1节 eop常见问题 1、未连接op/eop到电脑 2、有其他程序在使用op/eop&#xff08;同一时间只能有一个程序使用它&#xff09; 3、JTAG线未接 4、开发板未上电 5、oflash xxx.bin 时当前文件夹下没有xxx.bin 6、烧写完后没有正确设置启动开关 7、烧写完后&#xff0c;op…

HTML【基础篇】

HTML【基础篇】&#x1f34e;一.HTML结构&#x1f352;1.1认识HTML标签&#x1f352;1.2HTML文件基本结构&#x1f352;1.3标签层次结构&#x1f352;1.4快速生成代码框架&#x1f34e;二.HTML常见标签&#x1f352;1.1注释标签&#x1f352;1.2标题标签&#xff08;h1-h6&…

数据结构六:堆

前言&#xff1a;上一篇我们讲了二叉树&#xff0c;你知道吗&#xff1f;堆的底层是一棵完全二叉树。这样说会不会就会觉得熟悉了。 目录 1.堆的概念及存储方式 2&#xff1a;堆的创建 2.1:向下调整 3.堆的插入和删除 3.1&#xff1a;堆的插入 3.2&#xff1a;堆的删除 …

【数据库原理及应用】——数据查询SELECT(学习笔记)

&#x1f4d6; 前言&#xff1a;建立数据库的目的就是为了对数据库进行操作&#xff0c;以便能够从中提取有用的信息。从本节开始将介绍对数据库的操作&#xff0c;其中数据库查询是数据操作中的核心操作&#xff0c;SQL提供了SELECT语句对数据库进行查询操作。 目录&#x1f5…

Python-Flask虚拟环境(1)

windows环境下virtualenv和virtualenvwrapper创建虚拟环境一.virtualenv1.安装2.创建虚拟环境3.激活虚拟环境二、virtualenvwrapper1.安装2.创建虚拟环境3.进入/激活 虚拟环境4.退出虚拟环境5.删除虚拟环境6.列出所有环境7.进入到当前虚拟环境中8.进入到当前虚拟环境的site-pac…

gRPC(一)入门:什么是RPC?

目录前言一、RPC1、什么是RPC&#xff1f;2、HTTP和RPC的区别1&#xff09;概念区别2&#xff09;从协议上区分3、RPC如何工作的&#xff1f;4、RPC的优缺点5、常见的RPC框架1&#xff09;跟语言绑定框架2&#xff09;跨语言开源框架二、RPC快速入门1、简单的RPC示例1&#xff…

(八)Jmeter实现文件上传与下载

一、文件上传 文件上传接口: http://127.0.0.1/demo-api/uploadFile支持多文件同时上传 Jmeter操作步骤&#xff1a; 添加线程组添加取样器 - HTTP请求设置HTTP请求&#xff08;上传文件的HTTP请求&#xff09;设置协议、服务器地址、请求方式、上传接口路径选择文件上传tab输…

vs2019 编译调试 QT Creator 源码

vs2019 编译调试 QT Creator 源码 开始使用Qt Creator 5.15.2 调试编译 Qt Creator 6.0.2源码&#xff0c;对源码进行了 裁剪&#xff0c;将一些暂时用不到的文件删除&#xff0c;比如plugins里面的绝大部分文件。然后使用vs2019打开工程&#xff0c;进行编译调试。下面对这个…