信号量(semaphore[ˈseməfɔ:(r)])用在多线程多任务同步的,一个线程完成了某一个动做就经过信号量告诉别的线程,别的线程再进行某些动做。而互斥锁(Mutual exclusion,缩写 Mutex)是用在多线程多任务互斥的,一个线程占用了某一个资源,那么别的线程就没法访问,直到这个线程unlock,其余的线程才开始能够利用这个资源。好比对全局变量的访问,有时要加锁,操做完了,在解锁。尽管两个概念有点相似,可是他们的侧重点不同,信号量不必定是锁定某一个资源,而是流程上的概念,好比:有A,B两个线程,B线程要等A线程完成某一任务之后再进行本身下面的步骤,这个任务并不必定是锁定某一资源,还能够是进行一些计算或者数据处理之类。而线程互斥量则是“锁住某一资源”的概念,在锁按期间内,其余线程没法对被保护的数据进行操做。不难看出,mutex是semaphore的一种特殊状况(n=1时)。也就是说,彻底能够用后者替代前者。可是,由于mutex较为简单,且效率高,因此在必须保证资源独占的状况下,仍是采用这种设计。html
Semaphore能够被抽象为五个操做:
1.建立 Create,通常初始化一个值n
2.等待 Wait:线程等待信号量,若是值大于0,则得到,值减一;若是只等于0,则一直线程进入睡眠状态,知道信号量值大于0或者超时。
3.释放 Post:执行释放信号量,则值加一;若是此时有正在等待的线程,则唤醒该线程。
4.试图等待 TryWait:若是调用TryWait,线程并不真正的去得到信号量,仍是检查信号量是否可以被得到,若是信号量值大于0,则TryWait返回成功;不然返回失败。
5.销毁 Destroy
信号量,是能够用来保护两个或多个关键代码段,这些关键代码段不能并发调用。在进入一个关键代码段以前,线程必须获取一个信号量。若是关键代码段中没有任何线程,那么线程会当即进入该框图中的那个部分。一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。为了完成这个过程,须要建立一个信号量,而后将Acquire Semaphore VI以及Release Semaphore VI分别放置在每一个关键代码段的首末端。确认这些信号量VI引用的是初始建立的信号量。多线程
image.png
通常人不明白semaphore和mutex的区别,根本缘由是不知道semaphore的用途。semaphore的用途,一句话:调度线程。有的人用semaphore也能够把上面例子中的票“保护"起来以防止共享资源冲突,必须认可这是可行的,可是semaphore不是让你用来作这个的;若是你要作这件事,请用mutex。并发
在网上、包括stackoverflow等著名论坛上,有一个流传很广的厕所例子:mutex是一个厕所一把钥匙,谁抢上钥匙谁用厕所,谁没抢上谁就等着;semaphore是多个一样厕所多把一样的钥匙 ---- 只要你能拿到一把钥匙,你就能够随便找一个空着的厕所进去。事实上,这个例子对初学者、特别是刚刚学过mutex的初学者来讲很是糟糕 ----- 我第一次读到这个例子的第一反应是:semaphore是线程池???因此,请务必忘记这个例子。另外,有人也会说:mutex就是semaphore的value等于1的状况。这句话不能说不对,可是对于初学者来讲,请先把这句话视为错误;等你未来完全融会贯通这部分知识了,你才能真正理解上面这句话究竟是什么意思。总之请务必记住:mutex干的活儿和semaphore干的活儿不要混起来。post
在这里,我模拟一个最典型的使用semaphore的场景:a源自一个线程,b源自另外一个线程,计算c = a + b也是一个线程。(即一共三个线程)显然,第三个线程必须等第1、二个线程执行完毕它才能执行。在这个时候,咱们就须要调度线程了:让第1、二个线程执行完毕后,再执行第三个线程。此时,就须要用semaphore了。ui
int a, b, c; void geta() { a = calculatea(); semaphore_increase(); } void getb() { b = calculateb(); semaphore_increase(); } void getc() { semaphore_decrease(); semaphore_decrease(); c = a + b; } t1 = thread_create(geta); t2 = thread_create(getb); t3 = thread_create(getc); thread_join(t3); // semaphore的机制我在这里就不讲了,百度一下你就知道。 // semaphore_increase对应sem_post // semaphore_decrease对应sem_wait
简而言之,锁是服务于共享资源的;而semaphore是服务于多个线程间的执行的逻辑顺序的。spa
一:信号量与互斥锁之间的区别:.net
(1):互斥量用于线程的互斥,信号线用于线程的同步。这是互斥量和信号量的根本区别,也就是互斥和同步之间的区别。线程
(2):互斥量值只能为0/1,信号量值能够为非负整数。设计
也就是说,一个互斥量只能用于一个资源的互斥访问,它不能实现多个资源的多线程互斥问题。code
信号量能够实现多个同类资源的多线程互斥和同步。当信号量为单值信号量是,也能够完成一个资源的互斥访问。信号量是经过一个计数器控制对共享资源的访问,信号量的值是一个非负整数,全部经过它的线程都会将该整数减一。若是计数器大于0,则访问被容许,计数器减1;若是为0,则访问被禁止,全部试图经过它的线程都将处于等待状态。
计数器计算的结果是容许访问共享资源的通行证。所以,为了访问共享资源,线程必须从信号量获得通行证, 若是该信号量的计数大于0,则此线程得到一个通行证,这将致使信号量的计数递减,不然,此线程将阻塞直到得到一个通行证为止。当此线程再也不须要访问共享资源时,它释放该通行证,这致使信号量的计数递增,若是另外一个线程等待通行证,则那个线程将在那时得到通行证。
(3):互斥量的加锁和解锁必须由同一线程分别对应使用,信号量能够由一个线程释放,另外一个线程获得。
二:互斥和同步的定义
互斥:是指某一资源同时只容许一个访问者对其进行访问,具备惟一性和排它性。但互斥没法限制访问者对资源的访问顺序,即访问是无序的。
同步:是指在互斥的基础上(大多数状况),经过其它机制实现访问者对资源的有序访问。在大多数状况下,同步已经实现了互斥,特别是全部写入资源的状况一定是互斥的。少数状况是指能够容许多个访问者同时访问资源。
三:深刻解剖互斥量和信号量
互斥量(Mutex):
Mutex本质上说就是一把锁,提供对资源的独占访问,因此Mutex主要的做用是用于互斥。Mutex对象的值,只有0和1两个值。这两个值也分别表明了Mutex的两种状态。值为0, 表示锁定状态,当前对象被锁定,用户进程/线程若是试图Lock临界资源,则进入排队等待;值为1,表示空闲状态,当前对象为空闲,用户进程/线程能够Lock临界资源,以后Mutex值减1变为0。
Mutex能够被抽象为四个操做:
建立 Create
加锁 Lock
解锁 Unlock
销毁 Destroy
信号量:
信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们可以正确、合理的使用公共资源。
Semaphore能够被抽象为五个操做:
建立 (CreateSemaphore / sem_init)
等待 (WaitForSingleObject / sem _wait)
释放 (ReleaseMutex / sem _post)
试图等待 (WaitForSingleObject / sem _trywait)
销毁 (CloseHandle / sem_destroy)
1.https://www.zhihu.com/question/47704079
2.https://www.cnblogs.com/alinh/p/6905221.html
3.https://blog.csdn.net/daaikuaichuan/article/details/82950711#font_size5font_347