2

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);
}
4

5 回答 5

3

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

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

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

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

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

于 2010-10-21T23:32:32.500 回答
2

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

您人为地引入了共享资源(屏幕)并使其成为瓶颈。结果,关键部分竞争激烈。由于两个线程具有相同的优先级,因此 Windows 没有理由偏爱一个线程而不是另一个线程。减少上下文切换选择一个线程而不是另一个线程的原因。由于这种减少,共享资源的利用率上升。这是一件好事; 这意味着一个线程将更早完成而另一个线程将更早完成。

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

A B A B A B A B A B

AAAAA BBBBB

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

于 2010-10-22T10:48:48.257 回答
0

手波术语:

CriticalSection 是说线程想要控制一起做一些事情。

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

因此,您使用 CriticalSection 得到的是循环之间的失败。如果你有Sleep(0);之后,你可能会看到不同LeaveCriticalSection

于 2010-10-21T23:25:52.703 回答
0

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

于 2010-10-21T23:32:26.633 回答
0

从一些 MSDN 文档(http://msdn.microsoft.com/en-us/library/ms682530.aspx):

从带有 Service Pack 1 (SP1) 的 Windows Server 2003 开始​​,在临界区等待的线程不会以先到先服务的方式获取临界区。此更改显着提高了大多数代码的性能

于 2010-10-21T23:36:45.003 回答