?线程互斥? 库函数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;}
取出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上提供这把锁叫互斥量
互斥量的接口 初始化互斥量的两种方法
方法1:静态分配代码语言:javascript代码运行次数:0运行复制pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
销毁互斥量 销毁互斥量需要注意:
使用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;}
初始化
代码语言: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学习指南】线程同步与互斥的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号