0

我创建了一个多线程程序。这里一个线程打印“Hello”,另一个打印“World”,输出将是“Hello World”50 次。它工作正常,但它使用的是事件,它是内核对象,需要在用户模式和内核之间切换。任何人都可以在 VC++ 中建议任何更轻的版本,而不是 C# 或 java。

  #include <Windows.h>


static HANDLE event1 = CreateEvent(NULL, TRUE, TRUE, NULL); 
static HANDLE event2 = CreateEvent(NULL, TRUE, TRUE, NULL); 


DWORD WINAPI ThreadHello(  __in  LPVOID lpParameter)
{
    for( int i = 0 ; i < 50 ; i++ )
    {
        WaitForSingleObject(event1, INFINITE);
        ResetEvent(event1);
        printf("%s ", "Hello");
        SetEvent(event2);
    }

    return 1;
}

DWORD WINAPI ThreadWorld(  __in  LPVOID lpParameter)
{
    for( int i = 0 ; i < 50 ; i++)
    {
        WaitForSingleObject(event2, INFINITE);
        ResetEvent(event2);
        printf("%s\n", "World");
        SetEvent(event1);
    }

    return 1;
}


int _tmain(int argc, _TCHAR* argv[])
{
    CreateThread(NULL, 0, ThreadHello, (LPVOID)0, 0, 0);
    CreateThread(NULL, 0, ThreadWorld, (LPVOID)0, 0, 0);

    getchar();

    return 0;
}
4

4 回答 4

2

您为什么要在多个线程中执行此操作?现在您的线程正在以锁步方式执行,这意味着一次只有一个线程在运行。在这种情况下,我会重新设计以使用单个线程。

如果您这样做是为了代码清晰而不是并发执行(很少见,但仍有可能),请考虑使用fiber。代码结构与线程几乎相同,但不是设置和等待事件,而是通过调用SwitchToFiber抢占当前纤程以运行另一个纤程。

您应该使用多线程的主要情况是:

  1. 当您遇到可拆分为多个部分的受 CPU 限制的问题时 - 您的打印过程可能受 CPU 限制,但不能拆分为多个部分。您的文件读取问题可能与 CPU 无关。
  2. 在处理不支持异步调用的库时,您需要在后台运行一些东西。
  3. 因为它使您的代码更简单并且您不关心开销 - 例如在服务器应用程序中处理每个线程的一个请求时
于 2012-09-12T14:37:09.270 回答
1

尝试原子比较和交换,您忙于等待尝试获取锁。它很粗糙,因为它忙于等待,但它会给你一些有用的技术的经验。

于 2012-09-12T14:42:28.293 回答
1

我理解这个问题很笼统。这种情况也可以通过使用关键部分对象来解决。

DWORD WINAPI ThreadHello(  __in  LPVOID lpParameter)
{
  for( int i = 0 ; i < 50 ; i++ )
  {
    EnterCriticalSection(&csMyCriticalSectionObject);
    printf("%s ", "Hello");
    LeaveCriticalSection(&csMyCriticalSectionObject);
    // now we're ending the threads quantum
    Sleep(0);
    // ThreadWord is waiting on EnterCriticalSection, thus ready to execute and
    // therefore executed next.
  }
  return 1;
}

DWORD WINAPI ThreadWorld(  __in  LPVOID lpParameter)
{
  for( int i = 0 ; i < 50 ; i++)
  {
    EnterCriticalSection(&csMyCriticalSectionObject);
    printf("%s\n", "World");
    LeaveCriticalSection(&csMyCriticalSectionObject);
    // now we're ending the threads quantum
    Sleep(0);
    // ThreadHello is waiting on EnterCriticalSection, thus ready to execute and
    // therefore executed next.
  }
  return 1;
}


// global
CRITICAL_SECTION csMyCriticalSectionObject;


int _tmain(int argc, _TCHAR* argv[])
{
  // initialize the critical section object
  InitializeCriticalSection(&csMyCriticalSectionObject);

  CreateThread(NULL, 0, ThreadHello, (LPVOID)0, 0, 0);
  CreateThread(NULL, 0, ThreadWorld, (LPVOID)0, 0, 0);

  getchar();

  return 0;
}

当您需要多线程缓冲输出时,您应该考虑使用排队机制,例如同步 fifo。所有输出都可以由任意数量的线程排队到该队列中。单个输出线程可以出列到输出 (printf)。

于 2012-09-12T15:42:32.190 回答
0

问题域过于模糊和抽象,实际上不符合适当的多线程编程条件。我知道你正处于学习阶段,但你需要真实。您应该接受一些用户输入,读取一些文件,等待一些外部事件(如时间/时间,文件更改,用户登录,下载完成等),在线程(读取器线程,写入器线程)之间正确同步等等。

对于您遇到的问题,您可能想要使用关键部分或读写器锁。

于 2012-09-12T18:30:46.830 回答