繁体   English   中英

Windows关键部分的公平性

[英]Windows critical sections fairness

我对使用EnterCriticalSection和LeaveCriticalSection方法在Windows上关键部分的公平性存在疑问。 MSDN文档指定:“无法保证线程获得关键部分所有权的顺序,但是,该系统对所有线程都是公平的。” 问题出在我写的一个应用程序上,该应用程序阻塞了一些线程,即使经过很长时间,这些线程也从未进入关键部分。 所以我用一个简单的c程序进行了一些测试,以验证这种行为,但是当您有许多线程并且等待一些时间时,我注意到了奇怪的结果。 这是测试程序的代码:

CRITICAL_SECTION CriticalSection;

DWORD WINAPI ThreadFunc(void* data) {
  int me;
  int i,c = 0;;
  me = *(int *) data;
  printf(" %d started\n",me);
  for (i=0; i < 10000; i++) {
     EnterCriticalSection(&CriticalSection);
     printf(" %d Trying to connect (%d)\n",me,c);
     if(i!=3 && i!=4 && i!=5)
         Sleep(500);
     else
         Sleep(10);
    LeaveCriticalSection(&CriticalSection);
     c++;
     Sleep(500);
  }
  return 0;
}

int main() {
  int i;
  int a[20];
  HANDLE thread[20];

  InitializeCriticalSection(&CriticalSection);
  for (i=0; i<20; i++) {
        a[i] = i;
        thread[i] = CreateThread(NULL, 0, ThreadFunc, (LPVOID) &a[i], 0, NULL);
  }
}

结果是,某些线程被阻塞了许多个周期,而另一些线​​程则经常进入关键部分。 我还注意到,如果您更改了更快的“睡眠”(即10毫秒),则一切可能恢复正常,但我没有发现睡眠时间与公平之间有任何联系。 但是,这个测试示例比我的实际应用程序代码要好得多,后者要复杂得多,并且实际上显示了某些线程的饥饿。 为了确保饥饿的线程仍然存在并且可以正常工作,我进行了一个测试(在我的应用程序中),在该测试中,我在关键部分输入5次后杀死线程:结果是最后每个线程都进入了,所以我确保它们都还活着并在互斥锁上被阻止。 我是否必须假设Windows确实与线程不公平? 您知道这个问题的解决方案吗?

编辑:带有pthreads的linux中的相同代码,按预期工作(没有线程饥饿)。

EDIT2:我找到了一个可行的解决方案,使用CONDITION_VARIABLE强制公平。 可以从此帖子( 链接 )推断出该内容,并进行必要的修改。

由于关键部分举行了很长时间,因此您将在这里仍然遇到饥饿问题。
我认为MSDN可能暗示调度程序在唤醒线程方面是公平的,但是由于没有锁获取命令,因此它实际上可能不是您所期望的“公平”。 您是否尝试过使用互斥锁而不是关键区域? 另外,您是否尝试过调整旋转计数?

如果可以避免长时间锁定关键部分,那么这可能是处理此问题的更好方法。

例如,您可以将代码重构为具有一个用于处理长时间运行的操作的线程,而其他线程将对该线程的请求排队,从而阻止完成事件。 管理队列时,您只需要在短时间内锁定关键部分。 当然,如果这些操作也必须与其他操作互斥,那么您需要注意这一点。 如果所有这些东西不能同时运行,那么您也可以通过队列对其进行序列化。

另外,也许看看使用boost asio。 您可以使用线程池和绞线来防止多个异步处理程序并发运行,否则同步将成为问题。

我认为您应该回顾一些事情:

  • 在10000个案例中的9997个中,您分支到Sleep(500) 在几乎每次成功获取关键部分的尝试中,每个线程都会将主部分保留500毫秒。

  • 释放临界区后,线程执行另一个Sleep(500) 结果,通过保持关键部分,单线程几乎占据了可用时间的50%(49.985%)-无论如何!

  • 幕后花絮: Joe Duffy互斥锁的等待列表按FIFO顺序保存,并且OS始终在此类等待队列的开头唤醒线程。

假设您是故意这样做的,以显示行为:在处理器完全可用的情况下,启动这些线程中的20个可能导致最后一个线程最少等待10秒,以便最后一个线程访问单个逻辑处理器上的关键部分。测试。

您需要进行多长时间的测试/什么CPU? 以及什么Windows版本? 您应该能够写下更多的事实:线程活动与线程ID的直方图可以充分说明公平性。

关键部分应在短时间内获取。 在大多数情况下,共享资源可以更快地处理。 在关键区域内Sleep几乎肯定会指出设计缺陷。

提示:减少在关键部分内花费的时间或研究信号量对象

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM