2012-02-24 81 views
8

我想了解一些关于互斥量和信号量的说明。
我的问题是,互斥体和信号量实际上做了什么?

  1. 当一个线程试图进入一个互斥锁定的区域实际上做什么互斥, 一个。它等待锁被释放? 或b。它会进入睡眠状态,直到锁定释放。在那种情况下,当锁被释放时它是如何被唤醒的?
  2. 与1相同的问题,但在这种情况下,它是信号量。
  3. 你可以给我一些关于在C中忙于等待pthread的代码,以及线程进入睡眠而不是等待的情况吗?睡眠是不是意味着它被阻挡或睡觉是另一种忙碌的等待?
  4. 我想知道一些程序在这种情况下被覆盖,例如一些c源代码,在繁忙的等待,阻塞等实施。
+0

这是功课吗? – 2012-02-24 08:03:33

+0

不,我了解了繁忙的等待和阻塞线程同步的机制。但我不确定什么是互斥体和信号量。 – 2012-02-24 08:15:32

回答

5

当一个线程试图对一个互斥获取锁,如果该互斥锁已经被占用,那么通常它将使用对OS内核的调用来指示它正在等待,然后当当前持有该锁的线程解锁互斥锁时,它将调用OS内核来唤醒其中一个等待线程。

这同样适用于一个信号量,不同之处仅块,如果计数递减零下,并且当所述计数大于零增加回到线程仅唤醒。

忙等待是你在等待的东西时,不阻塞或睡眠,但是在一个循环反复轮询,因此处理器总是很忙,但没有做任何有用的事情。

要真正实现一个忙等待,你需要一个原子变量,但POSIX线程并没有提供这样的事情,所以你不能真正写在并行线程忙等待。您可以得到最接近的是锁定互斥锁,读取标志,解锁互斥锁,如果未设置标志,则循环。这会反复锁定和解锁互斥锁,但不会等待数据准备就绪。在这种情况下,你应该使用一个条件变量。

通常情况下,你说一个线程处于休眠状态,如果它已经呼吁像usleep中止自己的执行一段指定的时间。这与阻塞相反,它正在等待由另一个线程提供的特定信号。

+0

“,那么它会调用OS内核来唤醒其中一个等待线程。” 那么它意味着线程实际上在等待互斥锁或信号值下降时进入睡眠状态?他们没有在后台等待特定时间? – 2012-02-24 08:31:59

+2

它如何处理是操作系统的实现细节,但是等待线程通常不会消耗任何CPU。它被操作系统添加到等待线程列表中,并且只有在互斥信号被解锁时唤醒。 – 2012-02-24 08:49:01

+0

您可以使用pthreads来实现繁忙等待,这就是为什么有pthread_spin_ {init,destroy,lock,unlock,trylock}函数的原因。 – janneb 2012-02-24 08:51:38

-1

在简单的话互斥是当你关注1个锁定的东西....信号是多个锁.. 我会尽量给你寄样品。我记得我曾在C信号量和互斥有关的一些任务.. 就概念而言,这是有趣的东西在这里http://geekswithblogs.net/shahed/archive/2006/06/09/81268.aspx :)

感谢

+0

信号量也可以用于单个锁。 – 2012-02-24 08:05:05

0

它取决于互斥体的类型(它的后台实现),有些已经处于忙碌状态,有些会在内核线程对象中休眠,而后者会在互斥体更新时唤醒,有些则是混合(Valve的Source引擎使用混合引擎)。它的特性还取决于需要跨越内核/用户空间障碍的时间和频率,因为有时这可能比花更长的时间花费更多(如果想进一步了解事物的旋转与睡眠方面,请参见this)。

互斥通常用于一次单一线程的入口(尽管他们可支持由同一线程递归条目)。另一方面,信号量一次仅允许n线程尝试获取它(请参阅MSDN writeup或this比较Intel写法)。

睡眠线程通常意味着放弃它的分配计算时间片直到它准备好被唤醒,操作系统调度程序再给它一个时间片。你可能会发现的最好的例子实际上是在Linux内核源代码中(或者任何其他的开源操作系统)。

+0

您好,我特别感兴趣的是在linux C中实现posix线程。所以,从posix的角度来看,互斥和信号量究竟有什么作用?例如,如果我在C中编写代码,其中一些共享数据与互斥锁锁定,当其他线程访问时,它会等待吗?或只是阻止释放其资源?以及在信号量的情况下会发生什么。如果线程阻塞,那么在posix C中如何实现自旋和繁忙等待?条件变量是唯一的方法吗? – 2012-02-24 08:22:22

0
  1. 当一个线程试图进入一个互斥锁定的区域实际上做什么互斥体,一个。它等待锁被释放?或者b。它将进入 睡眠,直到锁定被释放。在那种情况下,当锁被释放时它又是如何被唤醒的 ?

当一个线程试图获取一个互斥锁,它被卡住且仅当锁被授予该线程返回。锁被操作系统识别,所以操作系统知道,直到这样一个锁可用于提供线程 - 它没有其他任何事情要做。线程驻留在OS内部。只有知道现在线程拥有所有权才能重新入睡的操作系统。在单个CPU系统中,在某些情况下,如果某个其他进程处于打开状态,互斥锁将仅在线程同时有效时才会返回 - CPU也可以同时锁定授予!

注意:当你做fwriteselect发生同样的事情。由于操作系统知道相应的IO需要花费时间,所以线程变得空闲。数据到达时,线程变为可运行。

  1. 与1相同的问题,但在这种情况下,它是信号量。你可以给我一些关于在C线程中等待线程的代码,还有一个线程进入睡眠而不是等待的例子吗?睡觉是不是意味着它是 被阻挡或睡觉是另一种忙碌的等待?

在这两种情况下,都没有忙等待。如果有人忙着等待,直到你获得锁定 - 你实际上没有达到锁定的目的!考虑一下,假设我们有严格的单个CPU情况(和一个愚蠢的操作系统)。那么会发生什么呢,线程1试图获取锁,因为锁在线程B中,因此线程A开始忙于等待。因此,CPU永远不会从线程A释放,线程B也不会有机会在CPU上执行 - 最终,两个线程都处于无用状态。锁对线程对象不做任何事情。但是,锁定的过程总是停线程

+0

嗨,那么你的意思是,如果有一些需要旋转的东西,我必须明确地实现这种繁忙的等待,即有一些变量或条件变量的权利?我的意思是互斥体和信号量不允许线程等待,对吧?例如,如果一个信号量被初始化为5,那么当它是5时,其他线程将被OS放入睡眠状态,直到信号量从5减少为止,然后线程将被操作系统唤醒,对吗? – 2012-02-24 08:31:25

+0

@Pbasak一旦线程获得互斥体的访问权限(或者如果满足信号量条件),线程现在是'runnable' - 系统中可能有许多可运行的线程,这取决于OS调度的其他方面。互斥量获取本身并不控制系统中的其他线程 - 但您的号码现在处于活动队列中。 – 2012-02-24 09:50:54

0

等待,睡觉,拦网,都意味着同样的事情:

  1. 线程进行系统调用(获得一个互斥体或信号,等待一段时间,等等)

  2. OS获取控制权,运行调度程序,将线程标记为等待资源,更新其他线程的状态,然后将控制权交给准备运行的线程。如果多个线程准备运行,则根据调度策略选择一个线程。

  3. 只要资源可用(通过另一个线程所做的另一个系统调用),调度程序就会将等待资源的状态更新为准备运行,并尽快对线程进行控制如调度程序策略决定的那样。

只要线程正在等待资源,它不会占用CPU。它没有投票。

3

请看看: https://stackoverflow.com/a/24582076/3163691

是,无论互斥信号进行同步,当一个线程试图获取他们的一个,这个线程被投入内核对象sleep如果该对象已被其他线程拥有。

正如你已经猜到了,这睡觉是一个重要的功能,因为它允许其他线程做更多有益的工作不仅仅是“循环/轮询”。

睡眠这些线程结束时,谁拥有对象发布它的线程。

[OS调度没有给出任何执行切片睡眠线程]。

& 自旋锁对比这其中线程在“循环/忙等待”状态浪费宝贵的CPU时间做几乎没有。因此,在用户代码中应该避免使用自旋锁。使用临界区,互斥量信号量代替!

从上面的链接可以看出,两个对象都不同,应该在正确的上下文中使用。一个互斥

觉得作为一个这使得刚刚一个线程拥有它。并且它有许多安全属性(所有权,终止通知,递归等)。

而且,认为信号作为这使得刚刚线程指定数量的拥有它。但是,它没有互斥量的许多有用属性。

希望这会有所帮助。