为什么使用pthread_mutex_lock,可以通过可编程方式完成相同的操作?

时间:2011-08-17 07:14:49

标签: linux pthreads critical-section

我们都知道信号量和临界区问题。

在pthread中,可以使用pthread_mutex_lock( )pthread_mutex_unlock( )对此进行排序。

但是为什么我们需要这些系统调用,当在代码中实现相同时,通过执行以下操作:

flag = 0;
if (flag) // Thread1 enters and makes flag = 0
{
   flag = 0; // On entering critical section, flag is made 0 so that others can't enter
  // do some critical section operation
  flag = 1;
}
// Thread1 exits

如上所述,它会解决临界区问题吗?如果不是,为什么呢?

4 个答案:

答案 0 :(得分:3)

使用操作这些对象的pthread_mutex对象和API而不是编写自己的同步原语的每个人,可能有很多原因。更重要的一个是偶然的:

  • 与许多对广大受众有用的其他对象和功能非常相似,标准化该功能是有意义的,这样人们就不必重新发明轮子,因此他们可以使用和识别标准模式和习语。换句话说,有pthread互斥API,原因与标准字符串操作函数相同。

  • 同步技术非常复杂,难以正确使用。因此,最好有一个经过审查的代码库来执行此功能。即使可以重新发明轮子数百万次,但99%的实施具有严重的缺陷并不是一个好的情况。例如,pthreads处理内存障碍和原子性等问题,这些问题在您的问题中没有正确解决。考虑到问题中的例子:至少有一个严重的问题;它有一个竞争条件,其中两个线程可以同时进入临界区,因为flag的测试并将其设置为0不是原子地执行。

答案 1 :(得分:2)

首先,如果您的代码有效,第二个线程将完全跳过关键部分。你必须在那里放置一个循环或其他东西。

另外,请考虑调度程序可能在任何地方抢占您的线程这一事实。如果线程A执行测试并且在更改flag之前被抢占,并且允许线程B进行测试并且之后很快就进入被抢占的关键部分,会发生什么。那里你有两个线程。

答案 2 :(得分:1)

首先,您应该使用原子内存操作(请参阅MSVC中的InterlockedCompareExchange()和GCC中的__sync_val_compare_and_swap())。

其次,这段代码可以正常工作,但只有当第一个线程第一次将标志设置回1时才应该等待。如果它应该,那么你将以循环结束,这将占用你所有的CPU。在这种情况下,你应该使用一些会导致等待线程休眠的东西(例如pthread_mutex_lock())。

答案 3 :(得分:1)

由于您使用“linux”标记了问题,因此可以补充一点,pthreads建立在称为“futexes”或“fast userspace mutexes”之上。正如名称所暗示的那样,快速路径,即锁定和解锁无争用的互斥锁,不需要系统调用,它都在用户空间中完成。 FWIW,AFAIK Windows也做类似的事情。