尝试使用 pselect() 阻止竞争条件,但信号不会中断

Trying to prevent race conditions with pselect(), but signal won't interupt

本文关键字:条件 信号 中断 竞争 pselect      更新时间:2023-10-16

我目前正在尝试使用套接字在c++中实现服务器。我试图通过阻塞SIGINT信号来防止竞争条件,直到它被卡在阻塞的pselect中。从那里,它应该退出,改变我的循环变量,然后退出线程。从我尝试使其工作来看,它似乎到达了pselect(),但使用我的代码不会中断它。如有任何帮助,不胜感激。

Listener.h:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
class CListener
{
public:
    CListener();
    void quitListener(void);
private:
    void* InitListener(void);
    static void* StartListenerThread(void* context);
    static bool mbListening;
    pthread_t mtThreadID;
};

Listener.cpp

#include <iostream>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <pthread.h>
#include <signal.h>
#include <errno.h>
#include "Listener.h"
bool CListener::mbListening = true;
CListener::CListener()
{
    mbListening = true;
    mtThreadID = 0;
    pthread_create(&mtThreadID, NULL, &CListener::StartListenerThread, this);
}
void* CListener::StartListenerThread(void* context)
{
    return ((CListener*)context)->InitListener();
}
void* CListener::InitListener()
{
    sigset_t tSignalSet;
    sigset_t tOriginalSignalSet;
    sigemptyset(&tSignalSet);
    sigaddset(&tSignalSet, SIGINT);
    sigprocmask(SIG_BLOCK, &tSignalSet, &tOriginalSignalSet);
    FD_ZERO(&tConnectionSet);
    FD_SET(0, &tConnectionSet);
    while(mbListening)
    {
            tSelectSet = tConnectionSet;
            std::cout << "Reached pselectn";
            nReadyConnections = pselect(nSelectSocket+1, &tSelectSet,
                                    NULL, NULL, NULL, &tOriginalSignalSet);
            std::cout << "Broke out of pselectn";
            if(nReadyConnections < 0 && errno == EINTR)
            {
                mbListening = false;
            }
    }
    pthread_exit(NULL);
    return NULL;
}
void CListener::quitListener()
{
    raise(SIGINT);
}

只要我正确地复制了所有内容手指交叉你应该可以运行:

CListener tListener = CListener();
usleep(20000);
tListener.quitListener();

,输出应显示在终端中。我的最终目标是允许pselect被中断,而不会中断后续的任何处理,并允许线程优雅地关闭。(block at pselect> receive SIGINT> interrupt pselect> return to loop> finish and exit)

我已经解决了自己的问题。因为我正在生成一个线程,所以我需要添加允许它的函数,以及添加一个信号处理程序,如下所示。

void CListener::quitListener()
{
    pthread_kill(mtThreadID,SIGINT);
}
void CListener::installSIGINTHandler()
{
    signal(SIGINT, CListener::SIGINTHandler);
}
void CListener::SIGINTHandler(int signo)
{
    mbListening = false;
}

并且需要将sig掩码设置更改为:

pthread_sigmask(SIG_BLOCK, &tSignalSet, &tOriginalSignalSet);