2010-10-21 65 views
2

为什么下面的代码示例会导致一个线程执行的方式比另一个更多,但互斥体不会呢?Windows 7中的关键部分问题

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

回答

0

在手波浪卷发方面:

CriticalSection的跟它的线程要控制做一些东西放在一起。

Mutex正在制作一个标记以显示“忙”,以便其他人可以等待并通知完成,以便其他人可以开始。已经在等待互斥体的其他人将抓住它,然后再次启动循环并将其恢复。

因此,使用CriticalSection获得的是循环之间的失败。如果您在LeaveCriticalSection之后有Sleep(0);

0

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

3

这可能无法回答您的问题,但在Windows Server 2003 SP1及更高版本中,关键部分的行为已更改。

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

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

有在MSDN page about critical sections

您可能还需要检查this forum post

+0

由于开关。论坛帖子似乎回答了这个问题。结论似乎是,关键部分不是共享资源(如日志文件等)的好方法。 – user483504 2010-10-22 00:02:45

+1

这不是一个正确的结论。关键部分应该非常好。只要磁盘带宽高于日志文件写入速率,所有线程最终都将被服务。当写入总速率超过磁盘带宽时,您遇到的问题比不公平的调度更大。 – MSalters 2010-10-22 10:37:50

0

从一些MSDN文档(http://msdn.microsoft.com/en-us/library/ms682530.aspx)是一个简短的说明一下:

启动与Windows Server 2003的Service Pack 1(SP1)中,等待关键部分的线程不会以先到先得的方式获取关键部分。对于大多数代码,此更改显着提高了性能

+0

该代码在XP上运行良好,但在同一硬件上不能运行。在显示的代码中,一个线程通常占主导地位,另一个线程每隔几秒就会运行一次。同样值得注意的是,SRW的行为方式是一样的。 – user483504 2010-10-21 23:53:56

2

关键部分(如互斥锁)旨在保护共享资源免遭冲突访问(例如并发修改)。关键部分是而不是,意在替换线程优先级。

您已经人为地引入了共享资源(屏幕)并将其变为瓶颈。因此,关键部分是高度争议的。由于两个线程具有相同的优先级,因此Windows没有理由将某个线程优先于另一个线程。减少上下文切换选择一个线程而不是另一个的理由。由于这种减少,共享资源的利用率上升。这是一件好事;这意味着前一个线程将完成批次,另一个线程将稍早完成。

看到效果图形,比较

A B A B A B A B A B 

AAAAA BBBBB 

第二序列是短,因为只有一个从A到B