【问题标题】:WinAPI's sleep doesn't work inside child threadWinAPI 的睡眠在子线程中不起作用
【发布时间】:2014-01-20 19:38:35
【问题描述】:

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

结果值:1000

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

【问题讨论】:

  • Sleep() API 按照任何线程中的指定工作。不能想象是不可能的。
  • 孩子总是睡不着。
  • CreateThread 是否返回没有错误?
  • @MartinJames,这是一个unsigned long long,但是是的,它不应该在那里。
  • @OP, MAXIMUM_WAIT_OBJECTS 为我报告 64。您正在尝试等待 1000。我通过检查 WaitForMultipleObjects 的返回值发现了这一点,正如您应该拥有的那样。

标签: c++ multithreading concurrency


【解决方案1】:

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 我一直忘记有限制。不错的收获。
【解决方案2】:

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)在几年前发表了一篇展示该技术的文章,但我不记得作者的名字了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-05
    • 2013-05-23
    • 2014-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-05
    • 2012-08-08
    相关资源
    最近更新 更多