Linux下线程的同步与互斥

一、线程的互斥

多个线程同时访问共享数据时可能会冲突,跟之前信号量的可重如性是同样的问题。如两个线程都要把某个全局变量增加1,这个操作在某平台需要三条指令完成:

1. 从内存读变量值到寄存器

2. 寄存器的值加1

3. 将寄存器的值写回内存

如下程序就会产生问题:

我们创建两个线程,每把g_count增加5000次,正常情况下最后g_count应该等于10000,但事实上每次运行该程序的结果都不一样。

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

Mutex用pthread_mutex_t类型的变量表示,可以这样创建和初始化

返回值:成功返回0,失败返回错误号。

把以上程序加锁后:

运行结果:

为了实现互斥锁操作,大多数体系结构都提供了swap或exchange指令,该指令的作用是把寄存器和内存单元的数据相交换,由于只有一条指令,保证了原子性,即使是多处理器平台,访问内存的总线周期也有先后,一个处理器上的交换指令执行时另一个处理器的交换指令只能等待总线周期。

lock:

movb $0,%al

xchgb &a1,mutex

if(a1寄存器的内容>0){

return 0;

}else

挂起等待;

goto lock;

unlock:

movb $1,mutex

唤醒等待mutex的线程;

return 0;

二、线程的同步

   线程的同步建立在互斥的基础之上,通常具有顺序性。当两个或多个线程互斥的访问一临界资源的时候,可能会引起死锁的现象。也可能会因为一直在竞争资源,都无法推进的情况。因此就需要线程间的同步。

线程间的同步还有这样一种情况:线程A需要等某个条件成立才能继续往下执行,现在这个条件不成立,线程A就阻塞等待,线程B在执行过程中使这个条件成立了,就唤醒线程A继续执行。在pthread库中通过条件变量(Condition Variable)来阻塞等待某个条件,或者唤醒等待这个条件的线程。Condition Variablepthread_cond_t类型的变量表,可以这样初始化和销毁:

返回值:成功返回0,失败返回错误号。

一个Condition Variable总是和一个Mutex搭配使用的。一个线程可以调用pthread_cond_wait在一个Condition Variable上阻塞等待,这个函数做以下三步操作:

1. 释放Mutex

2. 阻塞等待

3. 当被唤醒时,重新获得Mutex并返回

pthread_cond_timedwait函数还有一个额外的参数可以设定等待超时,如果到达了abstime所指定的时刻仍然没有别的线程来唤醒当前线程,就返回ETIMEDOUT。一个线程可以调用pthread_cond_signal唤醒在某个Condition Variable上等待的另一个线程,也可以调用pthread_cond_broadcast唤醒在这Condition Variable上等待的所有线程。

例如如下程序:

运行结果:

当pthread1不满足g_count的值大于等于20时就会执行上边pthread_cond_wait函数的三步操作:

1. 释放Mutex

2. 阻塞等待

3. 当被唤醒时,重新获得Mutex并返回

所以此时pthread2就会先执行,当满足g_count的值大于或等于20时pthread2才会被唤醒并获得互斥锁并执行。

时间: 2024-10-10 03:49:31

Linux下线程的同步与互斥的相关文章

Linux环境下线程的同步与互斥以及死锁问题

由于本次要讨论操作系统的死锁问题,所以必须先研究的是linux环境下的线程同步与互斥 先看下面的代码 大家猜想输出应该是什么呢? 结果是下面这个样子 好吧,似乎并没有什么区别... 那么下面再看这段代码(请无视并忽略屏蔽的内容...) 大家猜想正确的结果是什么呢?5000,10000? 好吧,或许你们都错了. 在运行了一段时间后,它的结果是这样的. 是不是又对又错? 为什么呢? 这就是因为程序中printf语句作用:本身是库函数,所以必须进行系统调用,必须进入内核进行切换,有很大概率形成数据的混

Linux之线程:同步与互斥

首先我们来说一下同步是什么: 其实所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回,同时其它线程也不能调用这个方法.按照这个定义,其实绝大多数函数都是同步调用(例如sin, isdigit等).但是一般而言,我们在说同步.异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务.例如Window API函数SendMessage.该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回.当对方处理完毕以后,该函数才把消息处理函数所返回的LRESULT值返回给

Linux环境下线程消息同步的陷阱

我们程序中常常会使用到线程间的消息同步处理,比如以下一段伪码 var message = "": void func()  {   1. 启动线程Thread(该线程中填充message的内容):   2. 阻塞,直到等待到完成message填充的事件:   3. 处理message:   .... } void Thread()  {   1. 通过某种处理填充message:   2. 触发func中的阻塞事件: } 我们通常会使用条件变量来完成类似情况的线程同步处理 比如wind

Linux 下线程的理解

2017-04-03 最近深入研究了下Linux线程的问题,发现自己之前一直有些许误解,特记之-- 关于Linux下的线程,各种介绍Linux的书籍都没有深入去解释的,或许真的如书上所述,Linux本质上不存在线程的概念!在某种程度上的确是这样,但是难道LInux就只有一种进程的东西么??答案肯定是否定的!下面咱们慢慢分析 说起Linux下的线程,的确不如windows下来的直接,windwos中进程和线程有着明确的区分,各自有自己代表的数据结构.操作API,进程享有资源和线程参加调度.一切都是

线程的同步与互斥,死锁

线程的同步与互斥 多个线程同时访问共享数据时可能会发生冲突,比如两个线程同时把一个全局变量加1,结果可能不是我们所期待的: 我们看这段代码的执行结果: #include <stdio.h> #include <stdlib.h> #include <pthread.h> static int g_count=0; void *thread(void *arg) { int index=0; int tmp=0; while(index++<5000) { tmp=

线程概念及线程的同步与互斥

线程概念:它是运行在进程内部的的一个基本执行流,多线程的控制流程可以长期并存,一个进程中的数据段和代码段都是被该进程中的多个线程共享的,若定义一个函数,每个线程都可以调用,若定义一个全局变量,每个线程都可以访问. 线程还共享进程的以下内容:1.文件描述符表 2.当前的工作目录 3.用户id(uid)和组id(gid) 4.每种信号的处理方式. 但每个线程还必须有自己的私有部分:1.线程id 2.硬件上下文(硬件寄存器的值,栈指针等) 3.自己的栈空间(运行时的临时数据都要保存在自己的栈空间上)

java的线程问题同步与互斥

以前学过java的线程,但是当时对Tread的理解不是很深,对于里面的同步与互斥,生产者与消费者问题,理解的不够深入,这次又从新学习java的多线程,感觉对线程的理解更加的深入了,觉得有必要写下博客记录下. 本文原创,转载请著明:http://blog.csdn.net/j903829182/article/details/38420503 1.java实现线程的方法: 1.实现Runnable接口,重写run方法,通过Thread的start方法启动线程.这种方法可以实现资源的共享 2.继承T

linux下数据库双向同步之mysql

环境:lamp 下搭建一个博客   然后实现同步 这里:以wordpress为例,进行实施 具体操作如下: 一.环境配置 1.自动获取ip地址,虚拟机设置为桥接 2.[[email protected] ~]# yum install wget #换成163的yum源: cd /etc/yum.repos.d mv CentOS-Base.repo CentOS-Base.repo.save wget mirrors.163.com/.help/CentOS5-Base-163.repo #wg

Linux下线程pid和tid

#include <stdio.h> #include <pthread.h> #include <sys/types.h> #include <sys/syscall.h> struct message { int i; int j; }; void *hello(struct message *str) { printf("child, the tid=%lu, pid=%d\n",pthread_self(),syscall(SYS