【发布时间】:2020-05-20 13:51:18
【问题描述】:
我目前正在开发一个使用 POSIX 线程实现两个线程(主线程和通信线程)的嵌入式应用程序(在 linux 4.14 上运行)。
通信线程创建一个 POSIX 队列来处理来自主线程的命令请求(通过调用 mq_send())。它还可以处理来自引发 SIGIO 信号的串行线路的传入数据。
这是一个示例代码
主线程:
pthread_t com_thread;
mqd_t cmd_queue;
void main (void)
{
struct mq_attr attr;
init_serial(); // Does serial line init and set a sigaction() with SIGIO that store serial data
// Create queue
attr.mq_flags = 0;
attr.mq_maxmsg = 100;
attr.mq_msgsize = sizeof(struct Dummy);
attr.mq_curmsgs = 0;
cmd_queue = mq_open(QUEUE_NAME, // Queue name
O_RDWR | O_CREAT, // Flags
S_IRWXU|S_IRWXG|S_IRWXO, // Mode
&attr); // Attributes
// Create thread
pthread_create(&com_thread, NULL, com_fw_handler, NULL);
while(1)
{
// Do some stuff ...
// Send command request
mq_send(cmd_queue, (const char*)cmd_request, sizeof(struct Dummy), 0);
}
}
Com 线程:
static void * com_fw_handler (void * ptr)
{
struct Dummy request_from_queue;
sigset_t sig_set;
int ret = 0;
// Allow SIGIO signal
sigemptyset(&sig_set);
sigaddset(&sig_set, SIGIO);
sigprocmask(SIG_UNBLOCK, &sig_set, NULL);
while(1)
{
// Wait for a command request or SIGIO
do
{
ret = mq_receive(cmd_queue, (char*)request_from_queue, sizeof(request_from_queue), NULL);
printf("mq_received() returned %d\n", ret);
if(ret > 0)
{
// Handle command request
}
}while(ret > 0);
// If mq_receive() exited because SIGIO has been raised
if((ret < 0) && (errno == EINTR))
{
// Handle incoming data from serial
}
}
}
当我尝试使用 GDB 调试我的应用程序时,一切正常,每次系统从串行线路接收数据时都会退出 mq_received()。这是控制台输出示例:
mq_received() returned 64
mq_received() returned -1
mq_received() returned 64
mq_received() returned -1
......
64 是 Dummy 结构的大小,-1 是引发 SIGIO 时的返回值。
如果应用程序直接在系统上启动,则会引发 SIGIO(我可以在控制台上看到调试打印),但 mq_receive() 似乎永远不会退出。 仅控制台输出:
mq_received() returned 64
mq_received() returned 64
.......
GDB 会话以以下“选项”开始:
handle all nostop pass noprint
我无法确定我观察到的行为是由于 GDB 信号处理还是比赛/计时问题或仅仅是开发人员问题!
我提供的示例代码有什么问题吗?
谢谢!
【问题讨论】:
-
如果您不使用
pthread_sigmask来控制哪个线程接收 SIGIO,您将遇到不可预知的行为。请注意,将 SIGIO 传递限制到它自己的线程会更好:即使您保证传递到 com_fw_worker 线程,您也可能会中断mq_receive以外的其他内容或完全错过信号。跨度> -
那么,最好的做法是将 SIGIO 传递给控制串行线路的线程(实际上是主线程),然后用 SIGUSR1 向 com 线程发送信号?因此,该 SIGUSR1 将仅被 com 线程捕获。
标签: linux multithreading queue signals posix