代码之家  ›  专栏  ›  技术社区  ›  EagleOne

消息队列中的两种消息

  •  10
  • EagleOne  · 技术社区  · 10 年前

    我在写一个程序,启动两个过程。

    第一个过程,“客户端”发送两种类型的消息。

    第一种类型增加共享资源(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);
    

    第三个线程使用互斥输入来增加资源的值。

    问题是服务器进程的线程1和线程2没有在它们应该终止的地方终止。事实上,在所有的增加/设置0消息之后,他们坚持使用第一个msgrcv()。所以问题是这两个线程无法侦听终止消息。

    我也尝试为第一条消息设置IPC_NOWAIT,但没有成功

    1 回复  |  直到 10 年前
        1
  •  9
  •   antiduh    10 年前

    你所依赖的是一个比赛条件,一个你几乎永远不会赢的条件。

    让我们来看看第一块:

    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”参数设置为 消息rcv ,它会给你所有的信息,然后你可以随心所欲地处理它。

      while(true) {
    
          // Get any msg type:           vv
          msgrcv( id_i, &msg, dimensione, 0, 0 );
    
          if ( msg.tipo == TERMINA ) {
              break;
          }
          else {
               // ...
          }
      }
    
    推荐文章