加入收藏 | 设为首页 | 会员中心 | 我要投稿 站长网 (https://www.zhandada.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 搭建环境 > Unix > 正文

Unix/linux进程及线程间同步技术总结

发布时间:2023-01-08 11:30:49 所属栏目:Unix 来源:互联网
导读: 为允许在线程或进程间共享数据,同步通常是必须的。常见的同步方式有:互斥锁、条件变量、读写锁、信号量。另外unix线程切换,对于进程间的同步,也可以通过进程间通信的方式进行同步,包括

为允许在线程或进程间共享数据,同步通常是必须的。常见的同步方式有:互斥锁、条件变量、读写锁、信号量。另外unix线程切换,对于进程间的同步,也可以通过进程间通信的方式进行同步,包括管道(无名管道、有名管道)、信号量、消息队列、共享内存、远程过程调用,当然也可以通过Socket来进行网络控制。

一. 互斥锁和条件变量是同步的基本组成部分

互斥锁和条件变量出自Posix.1线程标准,多用来同步一个进程中各个线程。但如果将二者存放在多个进程间共享的内存区中,它们也可以用来进行进程间的同步。

1. 互斥锁用于保护临界区,以保护任何时刻只有一个线程在执行其中的代码,其大体轮廓大体如下:

lock_the_mutex(...);

临界区

unlock_the_mutex(...);

下列三个函数给一个互斥锁上锁和解锁:

#include

int pthread_mutex_lock(pthread_mutex_t *mptr);//若不能立刻获得锁,将阻塞在此处

int pthread_mutex_trylock(pthread_mutex_t *mptr);//若不能立刻获得锁,将返回EBUSY,用户可以根据此返回值做其他操作,非阻塞模式

int pthread_mutex_unlock(pthread_mutex_t *mptr);//释放锁

互斥锁通常用于保护由多个线程或多个进程分享的共享数据(Share Data)

2. 条件变量,它是发送信号与等待信号。互斥锁用户上锁,条件变量则用于等待。一般来说,在一个进程/线程中调用pthread_cond_wait(..)等待某个条件的成立,此时该进程阻塞在这里,另外一个进程/线程进行某种操作,当某种条件成立时,调用pthread_cond_signal(...)来发送信号,从而使pthread_cond_wait(...)返回。此处要注意的是,这里所谈到的信号,不是系统级别的SIGXXXX信号,只是用信号这个词语更容易理解。条件变量与信号量更接近或者就可以认为是信号量。

下列两个函数用来对条件变量进行控制:

#include

int pthread_cond_wait(pthread_cond_t *cptr, pthread_mutex_t *mptr);

int pthread_cond_signal(pthread_cond_t *cptr);

由代码我们可以看出,条件变量的使用是需要结合锁机制的,即上面所提到的互斥锁。也就是说,一个进程/线程要等到临界区的共享数据达到某种状态时再进行某种操作,而这个状态的成立,则是由另外一个进程/线程来完成后发送信号来通知的。

其实想一想,pthread_cond_wait函数也可以用一个while死循环来等待条件的成立,但要注意的是,使用while死循环会严重消耗CPU,而pthread_cond_wait则是采用线程睡眠的方式,它是一种等待模式,而不是一直的检查模式。

总的来说,给条件变量发送信号的代码大体如下:

pthread_mutex_lock(&mutex);

设置条件为真

pthread_cond_signal(&cond);//发送信号

pthread_mutex_unlock(&mutex);

等待条件并进入睡眠以等待条件变为真的代码大体如下:

pthread_mutex_lock(&mutex);

while(条件为假)

pthread_cond_wait(&cond,&mutex);

执行某种操作

pthread_mutex_unlock(&mutex);

在这里需要注意的是,pthread_cond_wait(&cond,&mutex)是一个院子操作,当它执行时,首先对mutex解锁,这样另外的线程才能得到锁来修改条件,pthread_cond_wait解锁后,再将本身的线程/进程投入睡眠,另外,当该函数返回时,会再对mutex进行加锁,这样才能“执行某种操作”后unlock锁。

二、 读写锁

顾名思义,读写锁也是一种锁,他是在互斥锁的基础上进行了改进,当一个进程/线程获得写入锁时,其他的进程/线程仍然可以获得锁,只不过获得的是读取锁,因为一个进程/线程写入,不影响其他进程/线程的读操作。

三、 信号量

英文:semaphore,它是一种专门用于提供不同进程间或线程间同步手段的原语。可以通过下图来理解它。

进程A 进程B

\/

进程\ /

----------------------------------------------------

内核\/

信号量

也就是说,信号量是由内核来维护的,他独立出进程。因此可以通过它来进行同步。

上图一般来说,是基于Posix有名信号量,可以认为它是系统中的一个特殊文件(因为在Linux中,一切都可以认为是文件),因为在进程间的通信、同步中用的比较多,如果是线程之间的同步,经常用基于Posix内存的信号量。(基于内存的信号量必须在创建时指定是否在进程间共享,有名信号量随内核有持续性,需手工删除,而基于内存的信号量具有随进程的持续性)

对于信号量的工作原理,其实和互斥锁+条件变量相似。

主要函数有:sem_open、sem_close、sem_unlink,这里要注意,close只是关闭信号量,但并未从系统中删除,而unlink是删除该信号量。

sem_wait和sem_trywait函数,他们和pthread_cond_wait功能相似,都是等待某个条件的成立,sem_wait和sem_trywait的区别是,当所指定的信号量的值为0时,后者并不将调用者投入睡眠,而是立刻返回EAGAIN,即重试。

sem_post和sem_getvalue函数,sem_post将指定的信号量加一,然后唤醒正在等待该信号量值变为正数的任意线程。sem_getvalue是用来获取当前信号量值的函数。

总结:

互斥锁、条件变量、信号量三者的差别:

(1) 互斥锁必须总是由给他上锁的线程解锁(因为此时其他线程根本得不到此锁),信号量没有这种限制:一个线程等待某个信号量,而另一个线程可以挂出该信号量

(2)每个信号量有一个与之关联的值,挂出时+1,等待时-1,那么任何线程都可以挂出一个信号,即使没有线程在等待该信号量的值。不过对于条件变量来说,如果pthread_cond_signal之后没有任何线程阻塞在pthread_cond_wait上,那么此条件变量上的信号丢失。

(3)在各种各样的同步技巧中,能够从信号处理程序中安全调用的唯一函数是sem_post

(编辑:站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章