WinAPI的睡眠在子线程内部不起作用

时间:2014-01-20 19:38:36

标签: c++ multithreading concurrency

我是一个初学者,我试图重现一个rae条件,以便让自己熟悉这个问题。为此,我创建了以下程序:

#include <Windows.h>
#include <iostream>

using namespace std;

#define numThreads 1000

DWORD __stdcall addOne(LPVOID pValue)
{
    int* ipValue = (int*)pValue;
    *ipValue += 1;
    Sleep(5000ull);
    *ipValue += 1;
    return 0;
}

int main()
{
    int value = 0;
    HANDLE threads[numThreads];

    for (int i = 0; i < numThreads; ++i)
    {
        threads[i] = CreateThread(NULL, 0, addOne, &value, 0, NULL);
    }

    WaitForMultipleObjects(numThreads, threads, true, INFINITE);

    cout << "resulting value: " << value << endl;
    return 0;
}

我在线程函数中添加了睡眠,以便重现竞争条件,我理解,如果我只是添加一个作为工作负载,竞争条件不会表现出来:一个线程是创建,然后它运行工作负载,它恰好在另一个迭代创建的另一个线程开始其工作负载之前完成。我的问题是工作负载内的Sleep()似乎被忽略了。我将参数设置为5秒,我希望程序运行至少5秒,但它会立即完成。当我将Sleep(5000)置于main函数内时,程序按预期运行(> 5秒)。为什么Sleep内部线程被忽略? 但无论如何,即使Sleep()被忽略,程序也会在每次启动时输出:

结果值:1000

虽然正确的答案应该是2000.你能猜出为什么会这样吗?

2 个答案:

答案 0 :(得分:5)

WaitForMultipleObjects一次只允许等待最多MAXIMUM_WAIT_OBJECTS(当前是64个)线程。如果你考虑到这一点:

#include <Windows.h>
#include <iostream>

using namespace std;

#define numThreads MAXIMUM_WAIT_OBJECTS

DWORD __stdcall addOne(LPVOID pValue) {
    int* ipValue=(int*)pValue;
    *ipValue+=1;
    Sleep(5000);
    *ipValue+=1;
    return 0;
}

int main() {
    int value=0;
    HANDLE threads[numThreads];

    for (int i=0; i < numThreads; ++i) {
        threads[i]=CreateThread(NULL, 0, addOne, &value, 0, NULL);
    }

    WaitForMultipleObjects(numThreads, threads, true, INFINITE);

    cout<<"resulting value: "<<value<<endl;
    return 0;
}

......事情的发挥更像你期望的那样。当然,你是否真的会看到竞争条件的结果是一个相当不同的故事 - 但是在多次运行中,我确实看到了结果值的微小变化(例如,低于125左右)。

答案 1 :(得分:1)

Jerry Coffin有正确的答案,但只是为了省你打字:

#include <Windows.h>
#include <iostream>
#include <assert.h>

using namespace std;

#define numThreads 1000

DWORD __stdcall addOne(LPVOID pValue)
{
    int* ipValue = (int*)pValue;
    *ipValue += 1;
    Sleep(5000);
    *ipValue += 1;
    return 0;
}

int main()
{
    int value = 0;
    HANDLE threads[numThreads];

    for (int i = 0; i < numThreads; ++i)
    {
        threads[i] = CreateThread(NULL, 0, addOne, &value, 0, NULL);
    }

    DWORD Status = WaitForMultipleObjects(numThreads, threads, true, INFINITE);

    assert(Status != WAIT_FAILED);

    cout << "resulting value: " << value << endl;
    return 0;
}

如果出现问题,请确保已断言任何可能失败的Windows API函数的返回值。如果你真的非常需要等待很多线程,可以通过链接来克服64线程限制。即,对于您需要等待的每64个额外线程,您牺牲了一个线程,其唯一目的是等待64个其他线程,依此类推。我们(Windows Developer's Journal)多年前发表了一篇展示该技术的文章,但我无法回想起作者的名字。