Windows 7 中的临界区问题

发布于 2024-09-28 09:52:44 字数 2680 浏览 0 评论 0原文

为什么下面的代码示例会导致一个线程比另一个线程执行更多,而互斥体却不会?

#include <windows.h>
#include <conio.h>
#include <process.h>
#include <iostream>
using namespace std;

typedef struct _THREAD_INFO_ {

    COORD coord;        // a structure containing x and y coordinates
    INT threadNumber;   // each thread has it's own number
    INT count; 

}THREAD_INFO, * PTHREAD_INFO;

void gotoxy(int x, int y);

BOOL g_bRun; 
CRITICAL_SECTION g_cs; 

unsigned __stdcall ThreadFunc( void* pArguments )
{
    PTHREAD_INFO info = (PTHREAD_INFO)pArguments;

    while(g_bRun)
    {

        EnterCriticalSection(&g_cs); 

        //if(TryEnterCriticalSection(&g_cs))
        //{
            gotoxy(info->coord.X, info->coord.Y);
            cout << "T" << info->threadNumber << ": " << info->count;

            info->count++; 

            LeaveCriticalSection(&g_cs); 

        //}
    }

    ExitThread(0);
    return 0;
}

int main(void)
{
    // OR unsigned int
    unsigned int id0, id1; // a place to store the thread ID returned from CreateThread
    HANDLE h0, h1;  // handles to theads

    THREAD_INFO tInfo[2]; // only one of these - not optimal!

    g_bRun = TRUE;

    ZeroMemory(&tInfo, sizeof(tInfo)); // win32 function - memset(&buffer, 0, sizeof(buffer))

    InitializeCriticalSection(&g_cs); 

    // setup data for the first thread
    tInfo[0].threadNumber = 1;
    tInfo[0].coord.X = 0;
    tInfo[0].coord.Y = 0;

    h0 = (HANDLE)_beginthreadex( 
            NULL,        // no security attributes
            0,           // defaut stack size
            &ThreadFunc, // pointer to function
            &tInfo[0],   // each thread gets its own data to output
            0,           // 0 for running or CREATE_SUSPENDED 
            &id0 ); // return thread id - reused here

    // setup data for the second thread
    tInfo[1].threadNumber = 2;
    tInfo[1].coord.X = 15;
    tInfo[1].coord.Y = 0;

    h1 = (HANDLE)_beginthreadex( 
            NULL,        // no security attributes
            0,           // defaut stack size
            &ThreadFunc, // pointer to function
            &tInfo[1],   // each thread gets its own data to output
            0,           // 0 for running or CREATE_SUSPENDED 
            &id1 ); // return thread id - reused here

    _getch(); 

    g_bRun = FALSE; 

    return 0;
}

void gotoxy(int x, int y)   // x=column position and y=row position
{
   HANDLE hdl;
   COORD coords;
   hdl = GetStdHandle(STD_OUTPUT_HANDLE);
   coords.X = x;
   coords.Y = y;      
   SetConsoleCursorPosition(hdl, coords);
}

Why does the code sample below cause one thread to execute way more than another but a mutex does not?

#include <windows.h>
#include <conio.h>
#include <process.h>
#include <iostream>
using namespace std;

typedef struct _THREAD_INFO_ {

    COORD coord;        // a structure containing x and y coordinates
    INT threadNumber;   // each thread has it's own number
    INT count; 

}THREAD_INFO, * PTHREAD_INFO;

void gotoxy(int x, int y);

BOOL g_bRun; 
CRITICAL_SECTION g_cs; 

unsigned __stdcall ThreadFunc( void* pArguments )
{
    PTHREAD_INFO info = (PTHREAD_INFO)pArguments;

    while(g_bRun)
    {

        EnterCriticalSection(&g_cs); 

        //if(TryEnterCriticalSection(&g_cs))
        //{
            gotoxy(info->coord.X, info->coord.Y);
            cout << "T" << info->threadNumber << ": " << info->count;

            info->count++; 

            LeaveCriticalSection(&g_cs); 

        //}
    }

    ExitThread(0);
    return 0;
}

int main(void)
{
    // OR unsigned int
    unsigned int id0, id1; // a place to store the thread ID returned from CreateThread
    HANDLE h0, h1;  // handles to theads

    THREAD_INFO tInfo[2]; // only one of these - not optimal!

    g_bRun = TRUE;

    ZeroMemory(&tInfo, sizeof(tInfo)); // win32 function - memset(&buffer, 0, sizeof(buffer))

    InitializeCriticalSection(&g_cs); 

    // setup data for the first thread
    tInfo[0].threadNumber = 1;
    tInfo[0].coord.X = 0;
    tInfo[0].coord.Y = 0;

    h0 = (HANDLE)_beginthreadex( 
            NULL,        // no security attributes
            0,           // defaut stack size
            &ThreadFunc, // pointer to function
            &tInfo[0],   // each thread gets its own data to output
            0,           // 0 for running or CREATE_SUSPENDED 
            &id0 ); // return thread id - reused here

    // setup data for the second thread
    tInfo[1].threadNumber = 2;
    tInfo[1].coord.X = 15;
    tInfo[1].coord.Y = 0;

    h1 = (HANDLE)_beginthreadex( 
            NULL,        // no security attributes
            0,           // defaut stack size
            &ThreadFunc, // pointer to function
            &tInfo[1],   // each thread gets its own data to output
            0,           // 0 for running or CREATE_SUSPENDED 
            &id1 ); // return thread id - reused here

    _getch(); 

    g_bRun = FALSE; 

    return 0;
}

void gotoxy(int x, int y)   // x=column position and y=row position
{
   HANDLE hdl;
   COORD coords;
   hdl = GetStdHandle(STD_OUTPUT_HANDLE);
   coords.X = x;
   coords.Y = y;      
   SetConsoleCursorPosition(hdl, coords);
}

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

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

发布评论

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

评论(5

眼眸里的那抹悲凉 2024-10-05 09:52:45

我无法说出您为什么会观察到这种特定行为,但这可能与每种机制的实现细节有关。我可以说的是,解锁然后立即锁定互斥体是一件坏事。您最终会观察到奇怪的行为。

I can't say why you're observing this particular behavior, but it's probably to do with the specifics of the implementation of each mechanism. What I CAN say is that unlocking then immediately locking a mutex is a bad thing. You will observe odd behavior eventually.

浅忆流年 2024-10-05 09:52:45

来自一些 MSDN 文档 (http://msdn.microsoft.com/en-us/库/ms682530.aspx):

从带有 Service Pack 1 (SP1) 的 Windows Server 2003 开始​​,等待关键部分的线程不会按照先来先服务的方式获取关键部分。此更改显着提高了大多数代码的性能

From some MSDN docs (http://msdn.microsoft.com/en-us/library/ms682530.aspx):

Starting with Windows Server 2003 with Service Pack 1 (SP1), threads waiting on a critical section do not acquire the critical section on a first-come, first-serve basis. This change increases performance significantly for most code

尐偏执 2024-10-05 09:52:44

这可能无法回答您的问题,但关键部分的行为在 Windows Server 2003 SP1 及更高版本上发生了变化。

如果您遇到与 Windows 7 关键部分相关的错误,并且无法在 XP 计算机上重现,则您可能会受到该更改的影响。

我的理解是,在 Windows XP 上,关键部分使用了基于 FIFO 的策略,该策略对所有线程都是公平的,而更高版本则使用了旨在减少线程之间的上下文切换的新策略。

MSDN 页面上有关于关键部分的简短说明

您可能还想检查 此论坛帖子

That may not answer your question but the behavior of critical sections changed on Windows Server 2003 SP1 and later.

If you have bugs related to critical sections on Windows 7 that you can't reproduce on an XP machine you may be affected by that change.

My understanding is that on Windows XP critical sections used a FIFO based strategy that was fair for all threads while later versions use a new strategy aimed at reducing context switching between threads.

There's a short note about this on the MSDN page about critical sections

You may also want to check this forum post

不…忘初心 2024-10-05 09:52:44

关键部分(如互斥体)旨在保护共享资源免受冲突访问(例如并发修改)。关键部分旨在取代线程优先级。

您人为地引入了共享资源(屏幕)并使其成为瓶颈。因此,临界区的竞争非常激烈。由于两个线程具有相同的优先级,因此 Windows 没有理由优先选择一个线程而不是另一个线程。减少上下文切换是选择一个线程而不是另一个线程的原因。由于这种减少,共享资源的利用率提高了。这是一件好事;这意味着一个线程将提前完成很多,而另一个线程将提前完成一点。

要以图形方式查看效果,请比较

A B A B A B A B A B

第二

AAAAA BBBBB

个序列较短,因为从 A 到 B 只有一次切换。

Critical sections, like mutexes are designed to protect a shared resource against conflicting access (such as concurrent modification). Critical sections are not meant to replace thread priority.

You have artificially introduced a shared resource (the screen) and made it into a bottleneck. As a result, the critical section is highly contended. Since both threads have equal priority, that is no reason for Windows to prefer one thread over another. Reduction of context switches is a reason to pick one thread over another. As a result of that reduction, the utilization of the shared resource goes up. That is a good thing; it means that one thread will be finished a lot earlier and the other thread will finish a bit earlier.

To see the effect graphically, compare

A B A B A B A B A B

to

AAAAA BBBBB

The second sequence is shorter because there's only one switch from A to B.

七度光 2024-10-05 09:52:44

用波浪术语来说:

CriticalSection 表示线程想要控制一起做一些事情。

互斥体正在制作一个标记来显示“正忙”,以便其他人可以等待并通知完成,以便其他人可以开始。在您可以再次启动循环并将其取回之前,已经在等待互斥体的其他人会抓住它。

因此,您在 CriticalSection 中得到的结果是在循环之间无法屈服。如果在 LeaveCriticalSection 之后进行 Sleep(0);,您可能会看到差异

In hand wavey terms:

CriticalSection is saying the thread wants control to do some things together.

Mutex is making a marker to show 'being busy' so others can wait and notifying of completion so somebody else can start. Somebody else already waiting for the mutex will grab it before you can start the loop again and get it back.

So what you are getting with CriticalSection is a failure to yield between loops. You might see a difference if you had Sleep(0); after LeaveCriticalSection

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