0

0

【linux学习指南】线程同步与互斥

星夢妙者

星夢妙者

发布时间:2025-04-17 15:06:16

|

533人浏览过

|

来源于php中文网

原创

?线程互斥? 库函数strncpy?进程线程间的互斥相关背景概念临界资源:多线程执⾏流共享的资源就叫做临界资源临界区:每个线程内部,访问临界资源的代码,就叫做临界区互斥:任何时刻,互斥保证有且只有⼀个执⾏流进⼊临界区,访问临界资源,通常对临界资源起保护作⽤原⼦性(后⾯讨论如何实现):不会被任何调度机制打断的操作,该操作只有两态,要么完成,要么未完成?互斥量mutex⼤部分情况,线程使⽤的数据都是局部变量,变量的地址空间在线程栈空间内,这种情况,变量归属单个线程,其他线程⽆法获得这种变量。但有时候,很多变量都需要在线程间共享,这样的变量称为共享变量,可以通过数据的共享,完成线程之间的交互。多个线程并发的操作共享变量,会带来⼀些问题。

makefile文件

代码语言:javascript代码运行次数:0运行复制
<code class="javascript">bin=ticketcc=g++src=$(wildcard *.cc)obj=$(src:.cc=.o)$(bin):$(obj)$(cc) -o $@ $^ -lpthread%.o:%.cc@echo "Comiling $< to $@"$(cc) -c $< -std=c++17.PHONY:cleanclean:rm -f $(bin) $(obj).PHONY:testtest:echo $(src)echo $(obj)</code>

代码:

代码语言:javascript代码运行次数:0运行复制
<code class="javascript">#include <stdio.h>#include <string>#include <string.h>#include <pthread.h>#include <unistd.h>int ticket = 100;void* routine(void* args){    char *id = (char*)args;    // std::string id = static_cast<const char*>(args);    while(1)    {        if(ticket > 0)        {            usleep(10000);            printf("%s sells ticket:%d\n", id, ticket);            ticket--;        }        else        {            break;        }    }    return nullptr;}int main(void){    pthread_t t1, t2 , t3, t4;    pthread_create(&t1, nullptr, routine, (void*)"thread 1");    pthread_create(&t2, nullptr, routine, (void*)"thread 2");    pthread_create(&t3, nullptr, routine, (void*)"thread 3");    pthread_create(&t4, nullptr, routine, (void*)"thread 4");    pthread_join(t1, nullptr);    pthread_join(t2, nullptr);    pthread_join(t3, nullptr);    pthread_join(t4, nullptr);    return 0;}</code>
【linux学习指南】线程同步与互斥
【linux学习指南】线程同步与互斥
【linux学习指南】线程同步与互斥
【linux学习指南】线程同步与互斥
if语句判断条件为真以后,代码可以并发的切换到其他进程usleep这个模拟夜漫长业务的过程这个漫长的业务过程中,可能有多个线程会进入该代码段--ticket操作本身就不是一个原子操作

取出ticket–部分的汇编代码

代码语言:javascript代码运行次数:0运行复制
<code class="javascript">objdump -d a.out > test.objdump 152   40064b:   8b 05 e3 04 20 00     mov       0x2004e3(%rip),%eax 600b34 <ticket> 153   400651:   83 e8 01                 sub        $0x1,%eax154   400654:   89 05 da 04 20 00       mov%eax,0x2004da(%rip)  600b34 <ticket></code>

--操作并不是原子操作而是对应三条汇编指令:

load将共享变量体的从内存加载到寄存器update更新寄存器里面的只执行复议操作store:将新值从寄存器写回共享变量ticket的内存地址

要解决以上问题需要做到三点:

代码必须要有互斥行为:当代码进入临界区执行时,不允许其他进程进入该临界区如果多个线程同时要求进入临界区的代码,并且临界区没有线程在执行,那么只能一个线程进入该临界区如果现场不在临界区中执行,那么该现场就不能阻止其他进程进入临界区

要做到这三点,本身是上就是需要一把锁,linux上提供这把锁叫互斥量

【linux学习指南】线程同步与互斥

互斥量的接口 初始化互斥量的两种方法

方法1:静态分配代码语言:javascript代码运行次数:0运行复制
<code class="javascript">pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER </code>
⽅法2,动态分配: int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); 参数: mutex:要初始化的互斥量 attr:这是一个指向 pthread_mutexattr_t 类型对象的指针,该类型用于定义互斥锁的属性。如果将其设置为 NULL

销毁互斥量 销毁互斥量需要注意:

使用PTHREAD_ MUTEX_ INITIALIZER初始化的互斥量不需要销毁不要销毁⼀个已经加锁的互斥量已经销毁的互斥量,要确保后⾯不会有线程再尝试加锁代码语言:javascript代码运行次数:0运行复制
<code class="javascript">int pthread_mutex_destroy(pthread_mutex_t *mutex);</code>

互斥量加锁和解锁

免费语音克隆
免费语音克隆

这是一个提供免费语音克隆服务的平台,用户只需上传或录制一段 5 秒以上的清晰语音样本,平台即可生成与用户声音高度一致的 AI 语音克隆。

下载
代码语言:javascript代码运行次数:0运行复制
<code class="javascript">int pthread_mutex_lock(pthread_mutex_t *mutex);int pthread_mutex_unlock(pthread_mutex_t *mutex);返回值:成功返回o,失败返回错误号</code>

用pthread_ lock时,可能会遇到以下情况:

互斥量处于未锁状态,该函数会将互斥量锁定,同时返回成功发起函数调用时,其他线程已经锁定互斥量,或者存在其他线程同时申请互斥量,但没有竞争到互斥量,那么pthread_lock调用会陷入阻塞(执行流被挂起),等待互斥量解锁。

改进上面的售票系统:

代码语言:javascript代码运行次数:0运行复制
<code class="javascript">#include <stdio.h>#include <string>#include <string.h>#include <pthread.h>#include <unistd.h>int ticket = 100;pthread_mutex_t mutex;void* routine(void* args){    char *id = (char*)args;    // std::string id = static_cast<const char*>(args);    while(1)    {        pthread_mutex_lock(&mutex);        if(ticket > 0)        {            usleep(1000);            printf("%s sells ticket:%d\n", id, ticket);            ticket--;            pthread_mutex_unlock(&mutex);        }        else        {            pthread_mutex_unlock(&mutex);            break;        }    }    return nullptr;}int main(void){    pthread_t t1, t2 , t3, t4;    pthread_create(&t1, nullptr, routine, (void*)"thread 1");    pthread_create(&t2, nullptr, routine, (void*)"thread 2");    pthread_create(&t3, nullptr, routine, (void*)"thread 3");    pthread_create(&t4, nullptr, routine, (void*)"thread 4");    pthread_join(t1, nullptr);    pthread_join(t2, nullptr);    pthread_join(t3, nullptr);    pthread_join(t4, nullptr);    pthread_mutex_destroy(&mutex);    return 0;}</code>
【linux学习指南】线程同步与互斥
【linux学习指南】线程同步与互斥
?线程同步?条件变量当⼀个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了。例如⼀个线程访问队列时,发现队列为空,它只能等待,只到其它线程将⼀个节点添加到队列中。这种情况就需要⽤到条件变量。?同步概念与竞态条件同步:在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从⽽有效避免饥饿问题,叫做同步竞态条件:因为时序问题,⽽导致程序异常,我们称之为竞态条件。在线程场景下,这种问题也 不难理解? 条件变量函数

初始化

代码语言:javascript代码运行次数:0运行复制
<code class="javascript">int pthread_cond_init(pthread_cond_t *restrict cond,   const pthread_condattr_t*restrict attr);</code>

参数: cond:要初始化的条件变量 attr: NULL

销毁:

代码语言:javascript代码运行次数:0运行复制
<code class="javascript">int pthread_cond_destroy(pthread_cond_t *cond)</code>

等待条件满⾜

代码语言:javascript代码运行次数:0运行复制
<code class="javascript">int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrictmutex);参数:cond:要在这个条件变量上等待mutex:互斥量,后面详细解释</code>

唤醒等待

代码语言:javascript代码运行次数:0运行复制
<code class="javascript">int pthread_cond_broadcast(pthread_cond_t *cond);int pthread_cond_signal(pthread_cond_t *cond);</code>

简单案例:

我们先使用PTHREAD_COND/MUTEX_INITIALIZER进行测试,对其他细节暂不追究然后将接口更改成为使用pthread_cond_init/pthread_cond_destroy的方式,方便后续进行封装代码语言:javascript代码运行次数:0运行复制
<code class="javascript">#include <iostream>#include <string.h>#include <unistd.h>#include <pthread.h>pthread_cond_t cond = PTHREAD_COND_INITIALIZER;pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;void* active(void* args){    std::string name = static_cast<const char*>(args);    while(true)    {        pthread_mutex_lock(&mutex);        pthread_cond_wait(&cond, &mutex);        std::cout<< name << "活动..." << std::endl;        pthread_mutex_unlock(&mutex);    }}int main(){    pthread_t t1, t2;    pthread_create(&t1, nullptr, active, (void*)"thread -1");    pthread_create(&t2, nullptr, active, (void*)"thread -2");    sleep(3);    while(true)    {        //对比测试        pthread_cond_signal(&cond);//唤醒一个线程        // pthread_cond_broadcast(&cond);//唤醒所有线程        sleep(1);    }    pthread_join(t1, nullptr);    pthread_join(t2, nullptr);    pthread_cond_destroy(&cond);    pthread_mutex_destroy(&mutex);    return 0;}</code>
【linux学习指南】线程同步与互斥

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

254

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1089

2024.03.01

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

846

2023.08.22

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

562

2023.09.20

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1010

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

611

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

334

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

235

2025.08.29

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

3

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Excel 教程
Excel 教程

共162课时 | 21万人学习

Kotlin 教程
Kotlin 教程

共23课时 | 4.3万人学习

NumPy 教程
NumPy 教程

共44课时 | 3.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号