简单的多线程互斥示例不正确

发布于 2024-12-10 23:06:56 字数 856 浏览 0 评论 0原文

我希望以随机顺序获得从 0 到 4 的数字,但相反,我有一些不同步的混乱,

我做错了什么?

#include <iostream>
#include <windows.h>
#include <process.h>

using namespace std;

void addQuery(void *v );

HANDLE ghMutex;

int main()
{
    HANDLE hs[5];
    ghMutex = CreateMutex( NULL, FALSE, NULL);         
    for(int i=0; i<5; ++i)
    {
        hs[i] = (HANDLE)_beginthread(addQuery, 0, (void *)&i);
        if (hs[i] == NULL) 
        {
            printf("error\n"); return -1;
        }
    }

    printf("WaitForMultipleObjects return: %d error: %d\n",
         (DWORD)WaitForMultipleObjects(5, hs, TRUE, INFINITE), GetLastError());


    return 0;
}

void addQuery(void *v )
{
    int t = *((int*)v);
    WaitForSingleObject(ghMutex, INFINITE);

    cout << t << endl;

    ReleaseMutex(ghMutex);
    _endthread();
}

I expect to get numbers from 0 to 4 in random order, but instead, I have some unsynchronized mess

What i do wrong?

#include <iostream>
#include <windows.h>
#include <process.h>

using namespace std;

void addQuery(void *v );

HANDLE ghMutex;

int main()
{
    HANDLE hs[5];
    ghMutex = CreateMutex( NULL, FALSE, NULL);         
    for(int i=0; i<5; ++i)
    {
        hs[i] = (HANDLE)_beginthread(addQuery, 0, (void *)&i);
        if (hs[i] == NULL) 
        {
            printf("error\n"); return -1;
        }
    }

    printf("WaitForMultipleObjects return: %d error: %d\n",
         (DWORD)WaitForMultipleObjects(5, hs, TRUE, INFINITE), GetLastError());


    return 0;
}

void addQuery(void *v )
{
    int t = *((int*)v);
    WaitForSingleObject(ghMutex, INFINITE);

    cout << t << endl;

    ReleaseMutex(ghMutex);
    _endthread();
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

柠檬心 2024-12-17 23:06:56

您必须在锁内读取和写入共享变量。您在锁之外读取它,从而使锁变得无关紧要。

但即使这样还不够,因为您的共享变量是一个循环变量,您在没有锁保护的情况下写入该变量。一个更好的例子是这样运行的:

#include <iostream>
#include <windows.h>
#include <process.h>

using namespace std;

void addQuery(void *v );

HANDLE ghMutex;
int counter = 0;

int main()
{
    HANDLE hs[5];
    ghMutex = CreateMutex( NULL, FALSE, NULL);         
    for(int i=0; i<5; ++i)
    {
        hs[i] = (HANDLE)_beginthread(addQuery, 0, NULL);
        if (hs[i] == NULL) 
        {
            printf("error\n"); return -1;
        }
    }

    printf("WaitForMultipleObjects return: %d error: %d\n",
         (DWORD)WaitForMultipleObjects(5, hs, TRUE, INFINITE), GetLastError());


    return 0;
}

void addQuery(void *v)
{
    WaitForSingleObject(ghMutex, INFINITE);

    cout << counter << endl;
    counter++;

    ReleaseMutex(ghMutex);
    _endthread();
}

如果可以的话,使用临界区而不是互斥锁,因为它们使用起来更简单并且更高效。但它们具有相同的语义,因为它们只保护锁定块内的代码。

注意:Jerry 指出了一些其他问题,但我集中讨论了高级标题和序列化问题。

You have to read and write the shared variable inside the lock. You are reading it outside of the lock and thus rendering the lock irrelevant.

But even that's not enough since your shared variable is a loop variable that you are writing to without protection of the lock. A much better example would run like this:

#include <iostream>
#include <windows.h>
#include <process.h>

using namespace std;

void addQuery(void *v );

HANDLE ghMutex;
int counter = 0;

int main()
{
    HANDLE hs[5];
    ghMutex = CreateMutex( NULL, FALSE, NULL);         
    for(int i=0; i<5; ++i)
    {
        hs[i] = (HANDLE)_beginthread(addQuery, 0, NULL);
        if (hs[i] == NULL) 
        {
            printf("error\n"); return -1;
        }
    }

    printf("WaitForMultipleObjects return: %d error: %d\n",
         (DWORD)WaitForMultipleObjects(5, hs, TRUE, INFINITE), GetLastError());


    return 0;
}

void addQuery(void *v)
{
    WaitForSingleObject(ghMutex, INFINITE);

    cout << counter << endl;
    counter++;

    ReleaseMutex(ghMutex);
    _endthread();
}

If you can, use a critical section rather than a mutex because they are simpler to use and more efficient. But they have the same semantics in that they only protect code inside the locking block.

Note: Jerry has pointer out some other problems, but I've concentrated on the high level trheading and serialization concerns.

安人多梦 2024-12-17 23:06:56

您的同步存在一些问题,因为您希望以随机顺序获取 0 到 4 之间的数字。

问题是变量 i 是在锁之外写入的,每次执行线程调用 addQuery 方法时,它都会获取变量 的修改版本>我。这就是为什么您可能会看到 5 作为所有输出的值。

所以,这是我对这种情况的修复。您应该传递它的值,而不是在函数 addQuery 的参数中传递变量 i 的地址。希望有帮助:

#include <iostream>
#include <windows.h>
#include <process.h>

using namespace std;

void addQuery(void *v);

HANDLE ghMutex;

int main()
{
    HANDLE hs[5];
    ghMutex = CreateMutex(NULL, FALSE, NULL);
    for (int i = 0; i<5; ++i)
    {
        hs[i] = (HANDLE)_beginthread(addQuery, 0, (void *)i);

        if (hs[i] == NULL)
        {
            printf("error\n"); return -1;
        }
    }

    printf("WaitForMultipleObjects return: %d error: %d\n",
    (DWORD)WaitForMultipleObjects(5, hs, TRUE, INFINITE), GetLastError());


    return 0;
}

void addQuery(void *v)
{
    int t = (int)v;
    WaitForSingleObject(ghMutex, INFINITE);
    cout << t << endl;

    ReleaseMutex(ghMutex);
    _endthread();
}

Your synchronization has some issues as you want to get numbers from 0 to 4 in random order.

The problem is that the variable i is write outside the lock and every time the addQuery method get called by the execution of a thread, it get the modified version of variable i. That why you may see 5 as the value at the output for all.

So, here is my fix for this scenario. Instead of pass the address of variable i in parameters of the function addQuery, you should pass it's value. Hope it helps:

#include <iostream>
#include <windows.h>
#include <process.h>

using namespace std;

void addQuery(void *v);

HANDLE ghMutex;

int main()
{
    HANDLE hs[5];
    ghMutex = CreateMutex(NULL, FALSE, NULL);
    for (int i = 0; i<5; ++i)
    {
        hs[i] = (HANDLE)_beginthread(addQuery, 0, (void *)i);

        if (hs[i] == NULL)
        {
            printf("error\n"); return -1;
        }
    }

    printf("WaitForMultipleObjects return: %d error: %d\n",
    (DWORD)WaitForMultipleObjects(5, hs, TRUE, INFINITE), GetLastError());


    return 0;
}

void addQuery(void *v)
{
    int t = (int)v;
    WaitForSingleObject(ghMutex, INFINITE);
    cout << t << endl;

    ReleaseMutex(ghMutex);
    _endthread();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文