总结
豆包 AI 助手文章总结
首页 > 运维 > linux运维 > 正文

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

星夢妙者
发布: 2025-04-17 15:06:16
原创
490人浏览过

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

makefile文件

代码语言:javascript代码运行次数:0运行复制
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)
登录后复制

代码:

代码语言:javascript代码运行次数:0运行复制
#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;}
登录后复制
【linux学习指南】线程同步与互斥
【linux学习指南】线程同步与互斥
【linux学习指南】线程同步与互斥
【linux学习指南】线程同步与互斥
if语句判断条件为真以后,代码可以并发的切换到其他进程usleep这个模拟夜漫长业务的过程这个漫长的业务过程中,可能有多个线程会进入该代码段--ticket操作本身就不是一个原子操作

取出ticket–部分的汇编代码

代码语言:javascript代码运行次数:0运行复制
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>
登录后复制

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

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

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

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

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

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

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

方法1:静态分配代码语言:javascript代码运行次数:0运行复制
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER 
登录后复制
⽅法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运行复制
int pthread_mutex_destroy(pthread_mutex_t *mutex);
登录后复制

互斥量加锁和解锁

代码语言:javascript代码运行次数:0运行复制
int pthread_mutex_lock(pthread_mutex_t *mutex);int pthread_mutex_unlock(pthread_mutex_t *mutex);返回值:成功返回o,失败返回错误号
登录后复制

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

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

改进上面的售票系统:

代码语言:javascript代码运行次数:0运行复制
#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;}
登录后复制
【linux学习指南】线程同步与互斥
【linux学习指南】线程同步与互斥
?线程同步?条件变量当⼀个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了。例如⼀个线程访问队列时,发现队列为空,它只能等待,只到其它线程将⼀个节点添加到队列中。这种情况就需要⽤到条件变量。?同步概念与竞态条件同步:在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从⽽有效避免饥饿问题,叫做同步竞态条件:因为时序问题,⽽导致程序异常,我们称之为竞态条件。在线程场景下,这种问题也 不难理解? 条件变量函数

初始化

代码语言:javascript代码运行次数:0运行复制
int pthread_cond_init(pthread_cond_t *restrict cond,   const pthread_condattr_t*restrict attr);
登录后复制

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

销毁:

代码语言:javascript代码运行次数:0运行复制
int pthread_cond_destroy(pthread_cond_t *cond)
登录后复制

等待条件满⾜

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

唤醒等待

代码语言:javascript代码运行次数:0运行复制
int pthread_cond_broadcast(pthread_cond_t *cond);int pthread_cond_signal(pthread_cond_t *cond);
登录后复制

简单案例:

我们先使用PTHREAD_COND/MUTEX_INITIALIZER进行测试,对其他细节暂不追究然后将接口更改成为使用pthread_cond_init/pthread_cond_destroy的方式,方便后续进行封装代码语言:javascript代码运行次数:0运行复制
#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;}
登录后复制
【linux学习指南】线程同步与互斥

以上就是【linux学习指南】线程同步与互斥的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
豆包 AI 助手文章总结
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

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