0

サーバーには 2 つのスレッドがあり、1 つのワーカー スレッドと 1 つの受信スレッドがあります。このサーバーのすべてのアクティブなクライアントのリストを含む共有キューがあります。つまり、キューには各アクティブなクライアントの 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取り扱いがありません。WaitForSingleObjectWAIT_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 に答える