0

我的服务器上有两个线程,一个工作线程和一个接收线程。有一个共享队列,其中包含此服务器的所有活动客户端的列表,即队列具有每个活动客户端的 IP 和端口号

工作线程处于临界区,不断从队列中弹出数据,并向弹出的每个 IP 和端口号发送消息。

接收线程只等待新的连接,一旦除了活动客户端之外还有新客户端到达,接收线程立即希望工作线程离开临界区,以便接收线程可以进入临界区并写入队列。

如何做到这一点?有什么方法可以让线程在调用 EnterCriticalSection 时必须立即强制所有其他线程离开临界区并访问临界区(我猜这是某种优先级)。

在我的代码中,工作线程始终处于关键部分。当接收线程要进入临界区时,它设置一个事件,工作线程检查这个事件并离开临界区。然后,工作线程等待直到此事件被重置并再次获得关键部分的访问权限。

我的方法正确吗?有没有更好的方法来做到这一点?

   DWORD WINAPI workerThreadProcedure(LPVOID param)
   {
    struct node* sendBuff;
    char sendBuffer[600];
    while(1)
    {
       EnterCriticalSection(&cs);
       Sleep(500);
       if((WaitForSingleObject(data_available_event,0)) == WAIT_OBJECT_0 ) /*check for event*/
       {
         //Event is Set. Leave critical Section now
         LeaveCriticalSection(&cs); 
         while(WaitForSingleObject(data_available_event,0) == WAIT_OBJECT_0)
          {
           //Waiting to get REset \r\n");
          }
        //REset Done
        EnterCriticalSection(&cs); //again enter Critical Section.
       } 
       //Going to pop data out
       sendBuff = pop();
       while(sendBuff != NULL) // while Queue is not empty
       {
         //sendto() some data on socket
         sendBuff = pop();
       }
      LeaveCriticalSection(&cs);
    }
    return 0;
   }
DWORD WINAPI receiveThreadProcedure(LPVOID param)   
{
 //recvfrom()
 // if received Buffer is from a new Client
 SetEvent(data_available_event); /* signal worker thread that data is available and now I want to write to Queue*/
   struct node* cur;
   char clientPort[12], detail[512], *clientIP = inet_ntoa(clientSocket.sin_addr); 
   int cliPort = ntohs(clientSocket.sin_port);
   itoa(cliPort,clientPort,10);
   strcat(clientIP," ");
   strcpy(detail,clientIP);
   strcat(detail,clientPort);
   EnterCriticalSection(&cs);
   cur =cread();
   cur->data = detail;
   cur->n=NULL;
   push(cur);
   ResetEvent(data_available_event);
   LeaveCriticalSection(&cs);
}

编辑: 现在,当我运行此代码时,当新客户端到来时接收线程进入临界区,push()es 一些数据,然后重置事件,之后工作线程再次进入临界区,但随后在弹出时出现以下错误。

Master.exe 中 0x01031ba5 处的未处理异常:0xC0000005:访问冲突读取位置 0x00000000。

4

1 回答 1

2

workerThreadProcedure不必一直停留在临界区!查看代码中的位置Sleep(500):在关键部分内休眠 500 毫秒是没用的。

反而:

while(1)
{
   LeaveCriticalSection(&cs);
   Sleep(500);
   EnterCriticalSection(&cs);
   .
   .

这将在workerThreadProcedure不做任何事情时释放关键部分,您receiveThreadProcedure可以获取关键部分。

注1:

if((WaitForSingleObject(data_available_event,0)) == WAIT_OBJECT_0 ) 

没有else处理。WaitForSingleObject可能会返回与 WAIT_OBJECT_0 不同的结果。

笔记2:

while(WaitForSingleObject(data_available_event,0) == WAIT_OBJECT_0)
{
   //Waiting to get REset \r\n");
}
//REset Done

以 100% 的 CPU 运行。您可能希望提供一些重置事件的代码的 cpu 资源。考虑一个小睡眠,比如这个循环内的 Sleep(10)。

于 2013-06-05T17:29:02.980 回答