消息队列中的两种消息

时间:2016-01-31 16:43:54

标签: c multithreading multiprocess

我正在编写一个启动两个进程的程序。

第一个流程,"客户端"发送两种类型的消息。

第一种类型增加共享资源(int)。 第二种类型将资源设置为0。

在10条消息之后,客户端必须发送一条特殊类型的消息,该消息强制侦听两个队列的线程停止。因此,客户端在类型字段中发送两条带有特殊值的消息(每个队列一个),以便终止线程。

第二个过程是"服务器"。

服务器有三个线程:

第一个是倾听"增加"队列。它必须处理增加请求,直到终止消息。所以我写道:

do{
msgrcv(id_i,&msg,dimensione,INCREMENTA,0);
 pthread_mutex_lock(&mutex);
 printf("THREAD 1: Il contatore vale:%d\n",*contatore);
 incremento = msg.contenuto;
 printf("THREAD 1: Incremento di : %d\n",incremento);
  *contatore+=incremento;
 printf("THREAD 1: Il contatore vale:%d\n",*contatore);
 pthread_mutex_unlock(&mutex);
 msgrcv(id_i,&msg,dimensione,TERMINA,IPC_NOWAIT); //IPC_NOWAIT or the thread will
 freeze after the first message
}
while(msg.tipo!=TERMINA);

第二个必须处理"设置为0"请求直到终止消息。

do{msgrcv(id_a,&msg,dimensione,AZZERA,0);
pthread_mutex_lock(&mutex);
printf("THREAD 2: IL CONTATORE VALE:%d\n",*contatore);
*contatore=0;
printf("Thread 2: Contatore azzerato. Ora vale : %d\n",*contatore);
pthread_mutex_unlock(&mutex);
 msgrcv(id_a,&msg,dimensione,TERMINA,IPC_NOWAIT);//IPC_NOWAIT or the thread will
 freeze after the first message
 }
while(msg.tipo!=TERMINA);

第三个线程使用互斥锁增加资源的值以进入互斥。

问题是服务器进程的thread1和thread2没有终止它们应该的位置。事实上,他们在所有增加/ set0消息之后停留在第一个msgrcv()上。所以问题是两个线程无法监听终止消息。

我也尝试为第一个msgrcv设置IPC_NOWAIT但是没有工作

1 个答案:

答案 0 :(得分:8)

你依靠竞争条件,你几乎永远不会赢。

让我们来看看第一块:

do {
    // Note the msg type:           vvvvvvvvvv
    msgrcv( id_i, &msg, dimensione, INCREMENTA, 0 );

    // ...

    // Note the msg type:           vvvvvvv
    msgrcv( id_i, &msg, dimensione, TERMINA, IPC_NOWAIT );
}
while( msg.tipo != TERMINA );

循环中的第二个'msgrcv'调用是您尝试查找终结符消息类型,然后循环回到顶部并阻塞,等待另一条INCREMENTA消息。

考虑以下事件链:

   Sender              Receiver
   ---------------     -----------------
 1                      Call msgrcv with INCREMENTA. Block indefinitely
 2  Send 'INCREMENTA'
 3                      msgrcv returns. Begin processing increment msg.
 4                      Processing finshed.
 5                      Call msgrcv with TERMINA.
 6                      No TERMINA message found (queue empty), returns immediately.
 7                      Go to top of loop.
 8                      Call msgrcv with INCREMENTA. Block indefinitely
 9  Send 'TERMINA'      
10                      Nothing happens because we're waiting for 'INCREMENTA'.

您无法尝试在此模式中查询消息队列。如果事件8和9被颠倒过来,那么你的逻辑就会发生 - 但这是一种竞争条件,而且你可能会经常失去这种条件。

相反,为什么不使用msgrcv来接收任何类型的消息,然后在从队列中读取消息之后,找出你得到的消息类型并从那里处理它。如果您将0的'msgtyp'参数传递给msgrcv,它会为您提供所有消息,然后您可以随意处理。

  while(true) {

      // Get any msg type:           vv
      msgrcv( id_i, &msg, dimensione, 0, 0 );

      if ( msg.tipo == TERMINA ) {
          break;
      }
      else {
           // ...
      }
  }