无法使用pthread_kill和sigwait取消阻止/"唤醒"线程

Chr*_*ris 2 c c++ multithreading synchronization

我正在开发一个C/C++网络项目,并且在同步/发信号通知我的线程时遇到了困难.这是我想要完成的:

  1. 使用poll函数轮询一堆套接字
  2. 如果POLLIN事件中有任何套接字就绪,则向读取器线程和写入器线程发送信号以"唤醒"

我有一个名为MessageHandler的类,它设置信号掩码并生成读写器线程.在他们内部,我然后等待应该唤醒他们的信号.

问题是我通过向线程发送信号来测试所有这些功能,但它永远不会被唤醒.

这是问题代码并进一步说明.注意我刚刚强调了它如何与reader线程一起工作,因为writer线程基本相同.

// Called once if allowedSignalsMask == 0 in constructor
// STATIC
void MessageHandler::setAllowedSignalsMask() {
     allowedSignalsMask = (sigset_t*)std::malloc(sizeof(sigset_t));
     sigemptyset(allowedSignalsMask);
     sigaddset(allowedSignalsMask, SIGCONT);
}

// STATIC
sigset_t *MessageHandler::allowedSignalsMask = 0;

// STATIC
void* MessageHandler::run(void *arg) {
    // Apply the signals mask to any new threads created after this point
    pthread_sigmask(SIG_BLOCK, allowedSignalsMask, 0);

    MessageHandler *mh = (MessageHandler*)arg;
    pthread_create(&(mh->readerThread), 0, &runReaderThread, arg);

    sleep(1); // Just sleep for testing purposes let reader thread execute first
    pthread_kill(mh->readerThread, SIGCONT);
    sleep(1); // Just sleep for testing to let reader thread print without the process terminating

    return 0;
}

// STATIC
void* MessageHandler::runReaderThread(void *arg) {
    int signo;
    for (;;) {
            sigwait(allowedSignalsMask, &signo);

            fprintf(stdout, "Reader thread signaled\n");
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我取出了代码中的所有错误处理来压缩它,但确实知道线程正常启动并进入sigwait调用.

这个错误可能是显而易见的(它不是语法错误 - 上面的代码是从可编译的代码中压缩出来的,我可能会在编辑它时把它搞砸了)但我似乎无法找到/看到它,因为我花了很多钱时间在这个问题上,让自己迷茫.

让我解释一下我认为我在做什么以及它是否有意义.

  1. 在创建MessageHandler类型的对象时,它会将allowedSignalsMask设置为我有兴趣用来唤醒我的线程的一个信号(暂时)的集合.
  2. 我用pthread_sigmask将信号添加到当前线程的阻塞信号.在此之后创建的所有其他线程现在应该具有相同的信号掩码.
  3. 然后我用pthread_create创建reader线程,其中arg是指向MessageHandler类型的对象的指针.
  4. 我将sleep称为一种廉价的方式来确保我的readerThread一直执行到sigwait()
  5. 我将信号SIGCONT发送到readerThread,因为我对sigwait感兴趣,一旦接收它就会唤醒/解锁.
  6. 我再次将sleep称为一种廉价方式,以确保我的readerThread可以在从sigwait()唤醒/解除阻塞之后一直执行

其他有用的注释可能有用,但我认为不会影响问题:

  • 构造MessageHandler,然后在指向运行的函数指针的情况下创建不同的线程.该线程将负责创建读写器线程,使用poll函数轮询套接字,然后可能向读写器线程和写入器线程发送信号.

我知道它很长,但感谢你阅读它和你可以提供的任何帮助.如果我不够清楚,或者您觉得我没有提供足够的信息,请告诉我,我会更正帖子.

再次感谢.

R..*_*R.. 5

POSIX线程有条件变量是有原因的; 使用它们.在使用线程编程时,您不应该需要信号hackery来完成基本的同步任务.

这是一个很好的pthread教程,包含使用条件变量的信息:

https://computing.llnl.gov/tutorials/pthreads/

或者,如果你更舒适的旗语,您可以使用POSIX信号量(sem_init,sem_post,和sem_wait)来代替.但是一旦你弄清楚为什么条件变量和互斥配对是有意义的,我认为你会发现条件变量是一个更方便的原语.

另请注意,您当前的方法会在每次同步时产生多个系统调用(用户空间/内核空间转换).有了良好的pthreads实现,使用条件变量应该将其丢弃到最多一个系统调用,如果你的线程相互保持足够好以至于当它们仍然在用户空间中旋转时发生等待事件,则可能根本没有.