Windows 互斥和临界区之间的区别是什么?

Windows 互斥和临界区之间的区别是什么?,windows,linux,multithreading,programming-languages,Windows,Linux,Multithreading,Programming Languages,请从Linux、Windows的角度进行解释 我在用C语言编程,这两个术语会有什么不同吗。请尽可能多地张贴,并附上例子等 感谢您在Windows中,关键部分是您流程的本地部分。可以跨进程共享/访问互斥体。基本上,关键部分要便宜得多。不能具体评论Linux,但在某些系统上,它们只是同一事物的别名。互斥体是线程可以获取的对象,阻止其他线程获取它。它是咨询性的,不是强制性的;线程可以使用互斥表示的资源,而无需获取它 临界段是操作系统保证不被中断的代码长度。在伪代码中,它类似于: StartCritic

请从Linux、Windows的角度进行解释

我在用C语言编程,这两个术语会有什么不同吗。请尽可能多地张贴,并附上例子等


感谢您在Windows中,关键部分是您流程的本地部分。可以跨进程共享/访问互斥体。基本上,关键部分要便宜得多。不能具体评论Linux,但在某些系统上,它们只是同一事物的别名。

互斥体是线程可以获取的对象,阻止其他线程获取它。它是咨询性的,不是强制性的;线程可以使用互斥表示的资源,而无需获取它

临界段是操作系统保证不被中断的代码长度。在伪代码中,它类似于:

StartCriticalSection();
    DoSomethingImportant();
    DoSomeOtherImportantThing();
EndCriticalSection();

Critical Section和Mutex不是特定于操作系统的,它们是多线程/多处理的概念

临界截面 是一段代码,在任何给定时间只能由它自己运行(例如,有5个线程同时运行,一个名为“critical_section_function”的函数更新数组…您不希望所有5个线程同时更新数组。因此,当程序运行critical_section_function()时,则其他线程都不能运行其临界_section_函数

互斥体*
互斥是实现关键部分代码的一种方式(将其视为令牌…线程必须拥有它才能运行关键部分代码)

对于Windows,关键部分比互斥轻

互斥锁可以在进程之间共享,但总是导致对内核的系统调用,这会带来一些开销

关键部分只能在一个进程内使用,但其优点是,它们仅在争用情况下切换到内核模式-非争用获取(这应该是常见情况)速度非常快。在争用情况下,它们进入内核以等待某些同步原语(如事件或信号量)

我编写了一个快速示例应用程序,比较了两者之间的时间。在我的系统上,对于1000000次非竞争性采集和发布,互斥需要1秒以上。对于1000000次采集,关键部分需要约50毫秒

这是测试代码,我运行了这个,如果互斥是第一个或第二个,则得到了类似的结果,因此我们没有看到任何其他效果

HANDLE mutex = CreateMutex(NULL, FALSE, NULL);
CRITICAL_SECTION critSec;
InitializeCriticalSection(&critSec);

LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
LARGE_INTEGER start, end;

// Force code into memory, so we don't see any effects of paging.
EnterCriticalSection(&critSec);
LeaveCriticalSection(&critSec);
QueryPerformanceCounter(&start);
for (int i = 0; i < 1000000; i++)
{
    EnterCriticalSection(&critSec);
    LeaveCriticalSection(&critSec);
}

QueryPerformanceCounter(&end);

int totalTimeCS = (int)((end.QuadPart - start.QuadPart) * 1000 / freq.QuadPart);

// Force code into memory, so we don't see any effects of paging.
WaitForSingleObject(mutex, INFINITE);
ReleaseMutex(mutex);

QueryPerformanceCounter(&start);
for (int i = 0; i < 1000000; i++)
{
    WaitForSingleObject(mutex, INFINITE);
    ReleaseMutex(mutex);
}

QueryPerformanceCounter(&end);

int totalTime = (int)((end.QuadPart - start.QuadPart) * 1000 / freq.QuadPart);

printf("Mutex: %d CritSec: %d\n", totalTime, totalTimeCS);
HANDLE mutex=CreateMutex(NULL、FALSE、NULL);
临界截面;
初始化CriticalSection(&critSec);
大整数频率;
QueryPerformanceFrequency(&freq);
大整数开始、结束;
//强制代码进入内存,这样我们就看不到分页的任何效果。
EnterCriticalSection(&critSec);
离开临界区(&critSec);
QueryPerformanceCounter(&start);
对于(int i=0;i<1000000;i++)
{
EnterCriticalSection(&critSec);
离开临界区(&critSec);
}
QueryPerformanceCounter(&end);
int totalTimeCS=(int)((end.QuadPart-start.QuadPart)*1000/freq.QuadPart);
//强制代码进入内存,这样我们就看不到分页的任何效果。
WaitForSingleObject(互斥,无限);
释放互斥(mutex);
QueryPerformanceCounter(&start);
对于(int i=0;i<1000000;i++)
{
WaitForSingleObject(互斥,无限);
释放互斥(mutex);
}
QueryPerformanceCounter(&end);
整数总时间=(整数)((end.QuadPart-start.QuadPart)*1000/freq.QuadPart);
printf(“互斥锁:%d秒:%d\n”,totalTime,totalTimeCS);

除了其他答案外,以下详细信息针对windows上的关键部分:

  • 在没有争用的情况下,获取关键部分就像执行
    联锁比较交换
    操作一样简单
  • 临界区结构为互斥体保留空间。它最初是未分配的
  • 如果线程之间对关键部分存在争用,则将分配和使用互斥。关键部分的性能将降低到互斥的性能
  • 如果预计会出现高争用,则可以指定自旋计数来分配关键部分
  • 如果在具有自旋计数的关键部分上存在争用,则尝试获取关键部分的线程将自旋(忙等待)对于如此多的处理器周期。这可能会导致比睡眠更好的性能,因为执行上下文切换到另一个线程的周期数可能远远高于拥有线程释放互斥体的周期数
  • 如果自旋计数过期,将分配互斥锁
  • 当拥有线程释放关键部分时,需要检查是否分配了互斥体,如果分配了互斥体,则会将互斥体设置为释放等待的线程

在linux中,我认为它们有一个“旋转锁”,其作用类似于带有旋转计数的关键部分。

从理论角度来看,旋转锁是一段不能由多个线程同时运行的代码,因为代码访问共享资源

是一种用于保护关键部分的算法(有时是数据结构的名称)

和是互斥锁的常见实现

实际上,windows中有许多可用的互斥实现。它们的实现主要因锁定级别、作用域、成本以及在不同争用级别下的性能而有所不同。有关不同互斥实现的成本图表,请参阅

可用的同步原语

lock(object)
语句是使用-see实现的,以供参考

在过去的几年里,人们做了大量的研究。目标是以无锁或无等待的方式实现算法。在这种算法中,一个进程帮助其他进程完成它们的工作,以便该进程最终能够 ntdll!_RTL_CRITICAL_SECTION +0x000 DebugInfo : Ptr32 _RTL_CRITICAL_SECTION_DEBUG +0x004 LockCount : Int4B +0x008 RecursionCount : Int4B +0x00c OwningThread : Ptr32 Void +0x010 LockSemaphore : Ptr32 Void +0x014 SpinCount : Uint4B
int reentrant_function (int a, int b)
{
   int c;

   c = a + b;

   return c;
}
int result;

void non_reentrant_function (int a, int b)
{
   int c;

   c = a + b;

   result = c;

}