消息队列中的两种消息
Two types of message in a message queue
我正在编写一个启动两个进程的程序。
第一个进程,"client" 发送两种类型的消息。
第一种增加一个共享资源(int)。
第二种设置资源为0.
10 条消息后,客户端必须发送一条特殊类型的消息,强制停止监听两个队列的线程。因此,客户端发送两条消息(每个队列一条),在类型字段中具有特殊值以终止线程。
第二个进程是"server"。
服务器有三个线程:
第一个正在侦听 "increase" 队列。它必须处理增加请求直到终止消息。所以我写道:
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);
第二个必须处理 "set to 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 没有在它们应该终止的地方终止。事实上,他们在所有 increase/set0 消息之后停留在第一个 msgrcv() 上。所以问题是两个线程无法监听终止消息。
我也尝试为第一个 msgrcv 设置 IPC_NOWAIT 但没有成功
你依赖于一种你几乎永远不会赢的比赛条件。
我们来看看第一个区块:
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
来接收任何类型的消息,然后在从队列中读取消息后,找出您收到的消息类型并从那里进行处理。如果您将 'msgtyp' 参数的 0
传递给 msgrcv
,它将为您提供所有消息,然后您可以随意处理它。
while(true) {
// Get any msg type: vv
msgrcv( id_i, &msg, dimensione, 0, 0 );
if ( msg.tipo == TERMINA ) {
break;
}
else {
// ...
}
}
我正在编写一个启动两个进程的程序。
第一个进程,"client" 发送两种类型的消息。
第一种增加一个共享资源(int)。 第二种设置资源为0.
10 条消息后,客户端必须发送一条特殊类型的消息,强制停止监听两个队列的线程。因此,客户端发送两条消息(每个队列一条),在类型字段中具有特殊值以终止线程。
第二个进程是"server"。
服务器有三个线程:
第一个正在侦听 "increase" 队列。它必须处理增加请求直到终止消息。所以我写道:
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);
第二个必须处理 "set to 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 没有在它们应该终止的地方终止。事实上,他们在所有 increase/set0 消息之后停留在第一个 msgrcv() 上。所以问题是两个线程无法监听终止消息。
我也尝试为第一个 msgrcv 设置 IPC_NOWAIT 但没有成功
你依赖于一种你几乎永远不会赢的比赛条件。
我们来看看第一个区块:
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
来接收任何类型的消息,然后在从队列中读取消息后,找出您收到的消息类型并从那里进行处理。如果您将 'msgtyp' 参数的 0
传递给 msgrcv
,它将为您提供所有消息,然后您可以随意处理它。
while(true) {
// Get any msg type: vv
msgrcv( id_i, &msg, dimensione, 0, 0 );
if ( msg.tipo == TERMINA ) {
break;
}
else {
// ...
}
}