摘自:http://www.cnblogs.com/panda_lin/articles/1449139.html
多线程不仅仅是背几个API就能解决问题了
(英文版:http://msdn.microsoft.com/en-us/magazine/cc163405.aspx)介绍了Vista新增的同步原语,在讲到一下两段例子代码的时候有这么一段解释:
http://msdn.microsoft.com/zh-cn/magazine/cc163405.aspx
![条件变量的用法:CONDITION_VARIABLE - honesthu - 我的博客](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
for (unsigned int i = 0;i < g_uiIterations;i++)
{
EnterCriticalSection(&g_csLock);
// Produce work
g_listWork.push_back(i);
LeaveCriticalSection(&g_csLock);
WakeConditionVariable(&g_condNotEmpty);
Sleep(g_uiProducerDelay);
}
![条件变量的用法:CONDITION_VARIABLE - honesthu - 我的博客](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
while (true)
{
EnterCriticalSection(&g_csLock);
while (g_listWork.empty())
{
SleepConditionVariableCS(&g_condNotEmpty,&g_csLock,INFINITE);
}
i = g_listWork.front();
g_listWork.pop_front();
LeaveCriticalSection(&g_csLock);
wcout << L"Thread " << iThread << L" Consumed: " << i << endl;
Sleep(g_uiConsumerDelay); // Simulating work
}
当得到条件变量信号时,该线程醒来并在 SleepConditionVariableCS 函数返回之前再次自动锁定关键节。使用者线程然后往回循环,并再次查看队列是否为空。当线程被释放后,再次检测状态非常重要,因为其状态可能在使用者被释 放之前已被另一个线程更改;另外,条件变量还可能被骗醒 (spurious wakeup),这样它可能会在条件发生变化之前运行。
对于骗醒我一开始怎么也没想明白,SleepConditionVariableCS明明是个阻塞调用,在条件变量被唤醒之前是不可能进入临界区的,既然如此,用if等不就可以了吗?自己写了一段code调试后证明,这种思维不是多线程的。看以下例子:
1、队列已空,生产者线程A在push了一个元素后离开临界区,在调用WakeConditionVariable前被消费者线程B抢占。
2、消费者线程B检测到g_listWork不为空,消费掉1个元素后离开,同时消费者线程C继续抢占CPU资源。
3、消费者线程C检测到g_listWork为空,调用SleepConditionVariableCS等待条件变量,此时生产者线程A获得CPU资源并唤醒条件变量。
4、消费者线程C从SleepConditionVariableCS返回,注意,这时的g_listWork是空的,如果不用while循环检测,就真的是被骗醒了~~~
所以多线程编程不仅仅是掌握几个API,重要的是能具体情况具体分析,仔细考虑各种竞争条件并加以合理规划。当然,能避免多线程就尽量避免,另 外,VS2010在多线程方面增加了很多特性,无论是managed还是native编程,如果你要求不太高的话,多线程库会帮你做很多事情,看了演示后 还是很期待的。