两个线程中的同步问题使用关键部分共享队列以进行读取和写入

时间:2013-06-05 07:07:14

标签: c windows multithreading synchronization critical-section

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

工作线程处于严重部分,并不断将数据弹出队列,并向每个IP和端口号发送一条消息。

接收线程仅等待新连接,并且除了活动客户端之外的新客户端到达时,接收线程立即希望工作线程离开临界区,以便接收线程可以进入关键部分并写入队列。

如何实现这一目标?调用EnterCriticalSection时线程是否有任何方式必须立即强制所有其他线程离开临界区并访问Critical Section(我猜这是某种优先级)。

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

我的方法是否正确?有没有更好的方法呢?

   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:Access   违规读取位置0x00000000。

1 个答案:

答案 0 :(得分: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的代码 资源。考虑一个小睡眠,比如在这个循环中睡觉(10)。