如何在一个界面里面实施消息传递?

xtang 先生:
您好!
请问在Photon 里面,如何在一个界面里面实现消息的传递?

比如,在一个windows界面里面,有两个按钮:一个send button, 一个receive button. 另外,还有两个PtText文本框:一个接受消息,另一个接受回复的消息。我想在点击send button按钮后,发送一个“I am a student”的消息,然后点击receive按钮后,在接收消息的文本框内将“I am a student”的消息显示出来,同时,在回复一个消息到接收回复消息的文本框内将回复的内容显示出来。

可我们知道,消息传递是阻塞式的,当按下receive按钮后,整个屏幕就外于阻塞状态,这时send按钮就不能作用了。

请问我将如何解决这个问题呢?希望得到您的指点。急昐佳音!

你的MsgReceive()必须在另一个线程,收来的数据存起来。按receive button,只是去检查一下有没有收到数据。

xtang先生:
你说MsgReceive()必须在另一个线程,对此我不是很明白。可不可以再说详细些?

比如,我现在的程序中, send button 这个按钮与receive button 按钮是属于两个进程,你说MsgReceive () 必须在另一个线程。那么是哪个进程创建了这个线程呢?是在send button 这个进程里面还是在receive button这个进程里面呢?

这个问题还希望在你的空闲时候能够得到你详细的指点,我期盼你的消息。多谢!

Xtang 先生:
我一直在等着你的答复,对MsgReceive ()必须在另一个线程我真的不理解,请麻烦告之好吗?

MsgReceive()缺省处于阻塞状态,如果你不放在线程里,界面程序将会停在那里(因为它内部只有一个LOOP)。

我就是不知道MsgReceive ()放在哪个线程里面?这个线程是谁创建的呢?
是send button 按钮的代码创建的呢还是receive button 按钮的代码创建的呢?
请详细讲解一下可以吗?

各位师长, 小弟对此问题实在是无能为力, 真的希望能够得到各位高手的详细指点,希望各位高手不吝赐教!谢谢!

就是 receive button 的进程用pthread_create()自己创一个线程啊。这个线程没有别的事情,基本就是:

    /* create a channel */
    chid = ChannelCreate(...);
    printf("Channel ID is %d\n", chid);

    for (;;) {
          rcvid = MsgReceive(....);
           
          /* make sure this is a mesage for receive button */

          /* store message in a queue */
    }

然后receive button的callback里,只要做:

      if (message_queue_is_not_empty) {
          /* get the message */
 
          /* display the message */
      }

非常感谢!

xtang wrote:
就是 receive button 的进程用pthread_create()自己创一个线程
啊。这个线程没有别的事情,基本就是:

Code:
/* create a channel */
chid = ChannelCreate(…);
printf(“Channel ID is %d\n”, chid);

for (;:wink: {
rcvid = MsgReceive(…);

/* make sure this is a mesage for receive button */

/* store message in a queue */
}


然后receive button的callback里,只要做:

Code:
if (message_queue_is_not_empty) {
/* get the message */

/* display the message */
}


xtang先生:
我按照您的方法写了如下代码,可运行时,当我点击receive button之后,然后再点击sendbutton按钮,此时,在发送消息的文本框内,可以收到MsgReply回复的消息,可是receive button 接收的消息却不能显示出来。以下是我写的代码,希望您能给我一些指点,帮我找出所存在的问题。

/* Standard headers */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <mqueue.h>
#include <sys/iofunc.h>
#include <sys/dispatch.h>
#include <strings.h>

/* Local headers */
#include “ablibs.h”
#include “abimport.h”
#include “proto.h”

#define Q_FLAGS O_RDWR | O_CREAT
#define Q_PERM S_IRUSR | S_IWUSR | S_IROTH



void *thr_receive_msg( void * );
int
receive_msg( PtWidget_t *widget, ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo )

{
pthread_t tid;
pthread_attr_t thr_attr;
struct sched_param thr_param;
char buf[100];
mqd_t qd;
/* eliminate ‘unreferenced’ warnings */
widget = widget, apinfo = apinfo, cbinfo = cbinfo;

bzero ( buf, 100);

pthread_attr_init( &thr_attr );
thr_param.sched_priority = 22;
pthread_attr_setschedparam( &thr_attr, &thr_param );
pthread_attr_setschedpolicy( &thr_attr, SCHED_FIFO );
pthread_create( &tid, &thr_attr, &thr_receive_msg, NULL );
delay ( 500);

qd = mq_open ( “test_queue”, O_RDONLY);
if ( qd == -1 )
{
perror ( “Can not open the test_queue!\n”);
exit ( 1 );
}
else
{
if ( mq_receive ( qd, buf, 100, NULL) > 0)
{
printf ( “The receive msg is: %s\n”, buf );
PtTerminalPuts ( ABW_terminal, buf);
PtTerminalPuts ( ABW_terminal, “\r\n”);
}
mq_close ( qd );
}

return( Pt_CONTINUE );

}

void *thr_receive_msg ( void *a )
{
name_attach_t *attach;
char rmsg[100];
char buf[100];
int rcvid;
mqd_t qd;
struct mq_attr attr;

bzero( buf, 100);
bzero ( rmsg, 100 );

attr.mq_maxmsg = 100;
attr.mq_msgsize = 200;

attach = name_attach ( NULL, “set_text”, 0 );
for ( ; ; )
{
rcvid = MsgReceive ( attach → chid, &rmsg, sizeof ( rmsg ), NULL );
if ( rcvid > 0 )
{
qd = mq_open ( “test_queue”, Q_FLAGS, Q_PERM, &attr);
if ( qd == -1 )
{
perror ( “Can not create the test_queue\n”);
exit ( 1 );
}
else
{
sprintf ( buf, rmsg );
mq_send ( qd, buf, 100, 0 );
strcpy ( rmsg, “Send ok!” );
MsgReply ( rcvid, 1, &rmsg, sizeof ( rmsg));
}
mq_close ( qd );
}
}

你连mqueue都用上了,那开线程也可以省了。:smiley:

在 sender的main()里面,创立好mqueue.

  attr.mq_maxmsg = 100;
  attr.mq_msgsize = 200; 
  qd = mq_open ( "test_queue", O_RDRW|O_CREAT|O_NONBLOCK, Q_PERM, &attr);

要发message的时候,往mqueue 里送。

   sprintf ( buf, "I am a student" );
   mq_send ( qd, buf, strlen(buf), 0 );

在receiver的main()里面,连接mqueue.

   qd = mq_open("test_queue", O_RDONLY|O_NONBLOCK);

要收messge的时候,直接读mqueue.

   mq_receive(qd, buf, 100, NULL);

[quote=“xtang”]你连mqueue都用上了,那开线程也可以省了。:smiley:

xtang先生:您讲的这个方法我已经熟练撑握了,没有什么问题了。现在困扰我的就是如何才能连续不断地发送和接收消息。您告诉我创建线程,在创建的线程里面做我的for()死循环。对此问题我还不是很清楚。还希望您在空闲时间能够再次给我指点。郁闷的小弟在这里谢谢您了。

你是说,按下send message按钮后,就连续不断地发送消息吗? 那么什么时候停止呢?

void *send_forever(void *arg) {
   char buf[100];
   
   sprintf(buf, "I am a student");
   for (;;) {
         mq_send(qfd, buf, strlen(buf), 0);
   }
}

/* send button's call back */
pthread_create(0, 0, send_forever, 0);

至于“连续不断地接受”,也跟上面的意思差不多。

xtang先生:
请问PtTimer如何使用?我看了帮助文档,可上面讲的很简单。您能不能详细给我指点一下?最好能给我一个小例子参考一下,好吗?
小弟非常感谢!

呵呵,要注意的几个地方是:
在PhotonGUI里,有一个Loop,它的工作原理是:
for(;;){
MsgReceive (the event from photon space)
{
do refresh the widget or call the registered function attach to a widget
}
}

所以,一旦你在某个函数据阻塞了,那么photon无法响应界面的任何事件,因为它无法回到主循环中去接受控件事件.QNX Document里有这个情况的详细说明.你可以按QNX文档去step by step 解决这个问题.也可以按xtang的做法,创建一个线程,用这个线程来对外进行收发消息.Photon的消息可以pulse给这个线程,它不会被阻塞,这个线程收到外部的信息后,可以直接更新photon里的widget,如text label什么的.

[quote=“ChenYin”]呵呵,要注意的几个地方是:
在PhotonGUI里,有一个Loop,它的工作原理是:
for(;;){
MsgReceive (the event from photon space)
{
do refresh the widget or call the registered function attach to a widget
}
}

所以,一旦你在某个函数据阻塞了,那么photon无法响应界面的任何事件,因为它无法回到主循环中去接受控件事件.QNX Document里有这个情况的详细说明.你可以按QNX文档去step by step 解决这个问题.

请问QNX Document 什么地方讲到这个问题了?望告之!

[quote=“ChenYin”]呵呵,要注意的几个地方是:
在PhotonGUI里,有一个Loop,它的工作原理是:
for(;;){
MsgReceive (the event from photon space)
{
do refresh the widget or call the registered function attach to a widget
}
}

所以,一旦你在某个函数据阻塞了,那么photon无法响应界面的任何事件,因为它无法回到主循环中去接受控件事件.QNX Document里有这个情况的详细说明.你可以按QNX文档去step by step 解决这个问题.

请问QNX Document里什么地方有这个情况的详细说明.
麻烦告诉一下,好吗?

如果我没记错的话,photon programmer guide里有一章为"Interprocess Communication"是讲这个问题的