Linux系统编程之常用线程同步的三种方法

2023-11-06

Linux系统编程之线程同步高效率编程

         ~~~~~~~~         Linux系统中线程最大的特点就是共享性,线程同步问题较为困难也很重要,最常用的三种是:条件变量、互斥锁、无名信号量。(ps: 有名信号量可用于进程同步,无名信号量只能用于线程同步,是轻量级的。)


(一)、【互斥锁】:mutex

线程互斥量数据类型:pthread_mutex_t

  1. 初始化锁
    静态分配: pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    动态分配:int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr_t *mutexattr);
             ~~~~~~~~          参数一:创建的互斥锁
             ~~~~~~~~          参数二:存储互斥锁信息的结构,一般为NULL

  2. 加锁:对共享资源的访问,要对互斥量进行加锁,如果互斥量已经上了锁,调用线程会阻塞,直到互斥量被解锁。
    int pthread_mutex_lock(pthread_mutex *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex);
             ~~~~~~~~         参数:指明互斥锁

  3. 解锁:在完成了对共享资源的访问后,要对互斥量进行解锁
    int pthread_mutex_unlock(pthread_mutex_t *mutex);
             ~~~~~~~~         参数:指明互斥锁

  4. 销毁锁
    int pthread_mutex_destroy(pthread_mutex *mutex);
             ~~~~~~~~         参数:指明互斥锁


(二)、【条件变量】:cond

         ~~~~~~~~         条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。通常条件变量和互斥锁同时使用。
数据类型:pthread_cond_t

  1. 初始化
    静态:pthread_cond_t cond = PTHREAD_COND_INITIALIER;
    动态:int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
             ~~~~~~~~         参数一:指明条件变量
             ~~~~~~~~         参数二:存储条件变量属性的结构>
             ~~~~~~~~         
  2. 等待条件成立:释放锁,同时等待条件为真才能有停止阻塞。
    int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
             ~~~~~~~~         参数一:指明条件变量
             ~~~~~~~~         参数二:指明互斥锁
    int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);
             ~~~~~~~~         
  3. 激活条件变量:
    int pthread_cond_signal(pthread_cond_t *cond);
    int pthread_cond_broadcast(pthread_cond_t *cond); //解除所有线程的阻塞
      ~  
  4. 注销条件变量
    int pthread_cond_destroy(pthread_cond_t *cond);

(三)、【无名信号量】:sem

注意:链接需要加上-pthread选项
例如:gcc -pthread main.c -o main
  ~  
         ~~~~~~~~         有名信号量可用于进程的同步,头文件:#include<sys/sem.h>,;而无名信号量只能用于线程,是轻量级,头文件:#include <semaphore.h>)

  1. 初始化:
    int sem_init (sem_t *sem , int pshared, unsigned int value);
             ~~~~~~~~         参数一:指明信号量
             ~~~~~~~~         参数二:共享选项(linux 只支持为0,即表示它是当前进程的局部信号量)
             ~~~~~~~~         参数三:设置初始值
             ~~~~~~~~         
  2. 等待信号量:给信号量减1,然后等待直到信号量的值大于0。
    int sem_wait(sem_t *sem);
      ~  
  3. 释放信号量:
    int sem_post(sem_t *sem);
      ~  
  4. 销毁信号量:
    int sem_destroy(sem_t *sem);

【DEMO】

         ~~~~~~~~         现有两个同学打扫卫生,学生A负责扫地,学生B负责拖地,很明显要扫完地之后在拖地,由此引入线程同步。

1、条件变量和互斥锁的联合利用实现
#include <stdio.h>
#include <semaphore.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

#define DEBUG_INFO(...) printf("Info: "); printf(__VA_ARGS__)

void *student_1();
void *student_2();


int num = 0;	//共享资源
pthread_mutex_t mulock = PTHREAD_MUTEX_INITIALIZER;		//互斥锁
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;			//条件变量
pthread_t stu_thread[2];		//两个学生线程
int main()
{
	int i;
	
	// 创建两个学生线程
	pthread_create(&stu_thread[0], NULL, student_1, NULL);
	pthread_create(&stu_thread[1], NULL, student_2, NULL);
	
	// 等待两个线程结束
	for(i=0; i<2; i++)
	{
		pthread_join(stu_thread[i], NULL);
	}
	
	// 注销操作
	pthread_mutex_destroy(&mulock);
	pthread_cond_destroy(&cond);
	return 0;
}

void *student_1()
{
	int i;
	DEBUG_INFO("student a start work .\n");
	
	for(i=0; i<5; i++)
	{
		DEBUG_INFO("i = %d \n", i);
		pthread_mutex_lock(&mulock);	//锁住
		num++;		//扫一次地
		if(num >= 5)
		{
			DEBUG_INFO("student a finished work .\n");
			pthread_cond_signal(&cond);	//通知学生B已经扫完地了,并解锁
		}
		
		pthread_mutex_unlock(&mulock);
		sleep(1);
	}
	
	pthread_exit(NULL);
	return 0;
}
void *student_2()
{
	DEBUG_INFO("in student 2 .. \n");
	while(num < 5)		//不用if四因为需要防止莫名错误
	{
		pthread_cond_wait(&cond, &mulock);	//等待学生A扫地结束,等不到会再次一直阻塞
	}
	
	num = 0;	//拖地
	pthread_mutex_unlock(&mulock);
	DEBUG_INFO("student b finished work .\n");
	pthread_exit(NULL);
	return 0;
}


Makefile
这里写图片描述
运行结果
这里写图片描述
         ~~~~~~~~         由运行结果可见,学生A先完成工作,学生B在完成工作,所以成功实现线程同步。

2、信号量实现
/****************************************************************************************
* 文件名: demo2.c
* 创建者: 
* 时 间: 
* 联 系: 
* 简 介: 
*****************************************************************************************/

#include <stdio.h>
#include <semaphore.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

#define DEBUG_INFO(...) printf("Info: "); printf(__VA_ARGS__)

int num = 0;	//共享资源
sem_t mysem; //用于同步的信号量
pthread_t stu_thread[2];		//两个学生线程

void *student_1();
void *student_2();


int main()
{
	// 初始化信号量
	sem_init(&mysem, 0, 0);
	
	int i;
	
	// 创建两个学生线程
	pthread_create(&stu_thread[0], NULL, student_1, NULL);
	pthread_create(&stu_thread[1], NULL, student_2, NULL);
	
	// 等待两个线程结束
	for(i=0; i<2; i++)
	{
		pthread_join(stu_thread[i], NULL);
	}
	
	// 注销操作
	sem_destroy(&mysem);
	return 0;
}


void *student_1()
{
	int i;
	DEBUG_INFO("student a start work .\n");
	
	for(i=0; i<5; i++)
	{
		DEBUG_INFO("i = %d \n", i);
		num++;		//扫一次地
		if(num >= 5)
		{
			DEBUG_INFO("student a finished work .\n");
			sem_post(&mysem);	//释放信号量
		}
		
		sleep(1);
	}
	
	pthread_exit(NULL);
	return 0;
}
void *student_2()
{
	DEBUG_INFO("in student 2 .. \n");
	sem_wait(&mysem);		//等待信号量	
	num = 0;	//拖地
	DEBUG_INFO("student b finished work .\n");
	pthread_exit(NULL);
	return 0;
}


【运行结果】
这里写图片描述
         ~~~~~~~~         由运行结果可见,用信号量的程序运行结果与使用条件变量结果一致,所以实验成功!


end…

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux系统编程之常用线程同步的三种方法 的相关文章

随机推荐

  • 在线应用的 Serverless 实践

    作者 唐慧芬 黛忻 阿里云产品专家 导读 毫无疑问 Serverless 能够在效率和成本上给用户带来巨大收益 那具体到落地又应该怎么做呢 本文就给大家详细解读 Serverless 的落地实践 Serverless 落地企业级应用的挑战
  • XML外部实体漏洞(XXE)详解与编程

    XML外部实体漏洞 XXE 详解与编程 XML外部实体漏洞 XXE 是一种常见的网络安全漏洞 它允许攻击者通过操纵XML解析器来访问和读取服务器上的文件 甚至执行远程代码 本文将详细介绍XXE漏洞的原理和常见的攻击方式 并提供相应的源代码示
  • idea实现类快捷生成接口方法

    接口类 实现类 当我们实现了接口后 并没有像eclipse那样 鼠标放上去就会提示生成接口方法 鼠标定位到UserService类后面 快捷键 Alt Enter 选择Implement methods 选中点OK就自动生成了 还有一种方法
  • 《C++ Primer》读书笔记第十六章-1-定义模板

    笔记会持续更新 有错误的地方欢迎指正 谢谢 这一章特别实用 神器 gt 模板 泛型编程能处理在编译之前类型不知道的情况 在编译时获知类型 比如我们学过的容器 迭代器和算法都是泛型编程 模板是C 中泛型编程的基础 记住 一个模板就是一个创建类
  • netCDF文件的scale_factor和add_offset

    我使用python的netCDF4读取数据 发现数据集存在scale factor和add offset 但是我读取的数据应该是Unpacking data 也就是转换后的实际数据 不需要再处理 因为数据压缩是通过偏移和缩放之后将浮点数转化
  • 【C++】const修饰的成员函数

    在日常学习中总是碰到const修饰的成员函数 自己也总是稀里糊涂的 只能是靠着编译器来区分const和非const成员函数的相互调用关系 今天在这里总结以下 一 const修饰成员函数的格式 在成员函数的后边加上const void dis
  • NUC980开源项目11-启动方式

    上面是我的微信和QQ群 欢迎新朋友的加入 项目码云地址 国内下载速度快 https gitee com jun626 nuc980 open source project 项目github地址 https github com Jun117
  • Windows7/10上快速搭建Tesseract-OCR开发环境操作步骤

    之前在https blog csdn net fengbingchun article details 51628957 中描述过如何在Windows上搭建Tesseract OCR开发环境 那时除了需要clone https github
  • MySQL——事务和视图

    2023 9 17 本章开始介绍TCL语言 Transaction Control Language 事务控制语言 事务 事务的概念 一个或一组sql语句组成一个执行单元 这个执行单元要么全部执行 要么全部不执行 事务的特性 ACID 原子
  • scala---spark本地调式远程获取hdfs数据注意事项

    文章目录 前言 一 Hadoop配置注意事项 1 1 core site xml 1 2 core site xml 二 本地hadoop环境配置注意事项 三 本地scala项目spark代码调试 总结 前言 这篇文章主要帮大家绕开一些本地
  • 异常关机后Oracle无法正常连接,使用 conn /as sysdba 出现 ORA-01034 和 ORA-27101: shared memory realm does not exist...

    最近异常关机导致oracle无法连接 一直提示ORA 01034和ORA 27101的错误 打开cmd后 输入 sqlplus npolog conn as sysdba 提示 ORA 01034 Oracle not available
  • windows10使用WSL安装Linux(以ubuntu为例)

    1 安装工具WSL 适用于 Linux 的 Windows 子系统 WSL 可让开发人员直接在 Windows 上按原样运行 GNU Linux 环境 包括大多数命令行工具 实用工具和应用程序 且不会产生传统虚拟机或双启动设置开销 是win
  • 浙大水业oa系统服务器地址,OA系统

    OA系统功能定位于知识管理 企业决策支持 资源共享和企业协同工作 它由单纯的办公自动化向提升到协助管理整个企业为目标 表现在以下四个方面 把协同工作融入业务流程中 团队中通过及时的交流 准确的任务分派从而实现高绩效管理 E OFFICE办公
  • 通过js修改网页内容

    js可以通过文本所在标签的id获取该标签对象 然后修改其内容 如 document getElementById 标签id innerHTML 要修改的文本内容 该方法可以在要修改的文本内容中加html标签 如果只是纯文本的话 可以使用in
  • 严重性 代码 说明 项目 文件 行 禁止显示状态

    严重性 代码 说明 项目 文件 行 禁止显示状态 错误 LNK2019 无法解析的外部符号 public void thiscall LinkedList
  • 解决ubuntu无法输入中文标点

    使用Ctrl 切换
  • ListBox控件 滚动条

    今天在使用LISTBOX控件中遇到的一点小问题 主要是两个问题 水平滚动条不显示内容 垂直滚动条没有自动滚动 在网上查了一下找到了解决办法 原来只需要向控件发送消息就行了 具体代码如下 以下都是在Dialog类中的函数操作 如果是使用 Se
  • C++编程规范(101条规则、准则与最佳实践)

    C 编程规范 101条规则 准则与最佳实践 虽然是书本的目录 但也是高度的概括和总结 组织和策略问题 第0条 不要拘泥于小节 了解哪些东西不应该标准化 第1 条 在高警告级别干净利落地进行编译 第2 条 使用自动构建系统 第3 条 使用版本
  • 解决uniapp在微信小程序显示图片/数据,h5不显示图片/数据。

    配置跨域 首先在mainifest json中的源码视图中配置跨域 h5 devServer port 8080 disableHostCheck true proxy dpc target https www edonguoji cn c
  • Linux系统编程之常用线程同步的三种方法

    Linux系统编程之线程同步高效率编程 Linux系统中线程最大的特点就是共享性 线程同步问题较为困难也很重要 最常用的三种是 条件变量 互斥锁 无名信号量 ps 有名信号量可用于进程同步 无名信号量只能用于线程同步 是轻量级的 一 互斥锁