博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
线程的同步与互斥
阅读量:2242 次
发布时间:2019-05-09

本文共 2432 字,大约阅读时间需要 8 分钟。

线程的同步与互斥

每个线程专属的私有空间,其中上下文信息栈私有空间很是重要。

当多个线程在进程中运行时,他们看到同一份地址空间,这使得线程之间很容易的看到一份公共资源(临界资源),当多个线程看到同一份资源并对这份公共资源进行读写时,我们希望这份资源是原子性的,即我在使用这份资源时我不希望有其他执行流同时对这份资源进行读写操作。这就是为什么要引入线程的同步与互斥的原因。

mutex (互斥量)

多个线程同时访问共享数据时可能会冲突,例如 两个线程都要把某个全局变量增加1,这个操作在某平台需要三条指令完成:

  1. 从内存读变量值到寄存器
  2. 寄存器的值加1
  3. 将寄存器的值写回内存

假设两个线程在多处理器平台上同时执行这三条指令,则可能会导致错误的结果,比如说以下这种情况:

#include 
#include
#include
int g_val; int g_val; void* thread_val(void* arg) {
int i = 0; while (i < 500000) {
int tmp = g_val; g_val = tmp + 1; //printf("%d\n",g_val); i++; } } int main() {
pthread_t id1, id2; pthread_create(&id1, NULL, thread_val, NULL); pthread_create(&id2, NULL, thread_val, NULL); pthread_join(id1, NULL); pthread_join(id2, NULL); printf("%d\n",g_val); return 0; }

我们想要的结果是线程1和线程2在运行完之后将g_val的值加到一百万。实现结果:

pthread1

但明显并不能为什么呢

线程1刚把g_val从内存中取出来,准备对其运算,这时切换到另线程2,线程1会将g_val保存在他的上下文信息中(每个线程有自己私有的上下文信息),回到线程2,如果他将g_val又从内存中取出来,在CPU上经过各种运算再把它放回内存。这时切换回线程1,因为线程一从CPU拿出来的变量保存在他的上下文信息中,所以在g_val被线程2改变后,线程1保存在上下文中的g_val并没有改变,线程1把g_val放入CPU,经过各种运算放回内存,这时线程2的工作就会被线程1覆盖。我们并不希望这样

对于多线程的程序,访问冲突的问题是很普遍的,解决的办法是引入互斥锁(Mutex,Mutual Exclusive Lock),获得锁的线程可以完成“读-修改-写”的操作,然后释放锁给其它线程,没有获得 
锁的线程只能等待而不能访问共享数据,这样“读-修改-写”三步操作组成一个原子操作,要么都执行,要么都不执行,不会执行到中间被打断,也不会在其它处理器上并行做这个操作。

返回值:成功返回0,失败返回错误号。 
pthread_mutex_init函数对Mutex做初始化,参数attr设定Mutex的属性,如果attr为NULL则表示缺省属性。 
pthread_mutex_init函 数初始化的Mutex可以用pthread_mutex_destroy销毁。如果Mutex变量是静态分配的(全局变量 或static变量),也可以用宏定义PTHREAD_MUTEX_INITIALIZER

#include 
#include
#include
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; int g_val; void* thread_val(void* arg) {
int i = 0; while (i < 500000) { pthread_mutex_lock(&lock);//lock here int tmp = g_val; g_val = tmp + 1; //printf("%d\n",g_val); pthread_mutex_unlock(&lock);//unlock here i++; } } int main() {
pthread_t id1, id2; pthread_create(&id1, NULL, thread_val, NULL); pthread_create(&id2, NULL, thread_val, NULL); pthread_join(id1, NULL); pthread_join(id2, NULL); pthread_mutex_destroy(&lock);//destroy lock printf("%d\n",g_val); return 0; }

运行结果

pthread2

转载地址:http://ntgbb.baihongyu.com/

你可能感兴趣的文章
Logistic regression 为什么用 sigmoid ?
查看>>
Logistic Regression 为什么用极大似然函数
查看>>
LightGBM 如何调参
查看>>
用 TensorFlow.js 在浏览器中训练神经网络
查看>>
梯度消失问题与如何选择激活函数
查看>>
为什么需要 Mini-batch 梯度下降,及 TensorFlow 应用举例
查看>>
为什么在优化算法中使用指数加权平均
查看>>
初探Java设计模式5:一文了解Spring涉及到的9种设计模式
查看>>
Java集合详解1:一文读懂ArrayList,Vector与Stack使用方法和实现原理
查看>>
Java集合详解2:一文读懂Queue和LinkedList
查看>>
Java集合详解3:一文读懂Iterator,fail-fast机制与比较器
查看>>
Java集合详解4:一文读懂HashMap和HashTable的区别以及常见面试题
查看>>
Java集合详解5:深入理解LinkedHashMap和LRU缓存
查看>>
Java集合详解6:这次,从头到尾带你解读Java中的红黑树
查看>>
Java集合详解8:Java集合类细节精讲,细节决定成败
查看>>
Java并发指南2:深入理解Java内存模型JMM
查看>>
Java并发指南5:JMM中的final关键字解析
查看>>
Java并发指南6:Java内存模型JMM总结
查看>>
Java并发指南7:JUC的核心类AQS详解
查看>>
Java并发指南8:AQS中的公平锁与非公平锁,Condtion
查看>>