【发布时间】:2014-06-24 07:15:21
【问题描述】:
我对使用 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 对线程真的不公平? 你知道这个问题的任何解决方案吗?
编辑:在 linux 中使用 pthreads 的相同代码,按预期工作(没有线程饿死)。
EDIT2:我找到了一个可行的解决方案,强制公平,使用 CONDITION_VARIABLE。 可以从这篇文章 (link) 中推断出来,并进行必要的修改。
【问题讨论】:
标签: c++ c windows multithreading critical-section