gpt4 book ai didi

c++ - 如何在超时内从另一个线程唤醒 select()

转载 作者:IT王子 更新时间:2023-10-29 01:09:35 24 4
gpt4 key购买 nike

根据“man select”信息:

     "On  success,  select() and pselect() return the number of file descrip‐
tors contained in the three returned descriptor sets which may be zero
if the timeout expires before anything interesting happens. On error,
-1 is returned, and errno is set appropriately; the sets and timeout become
undefined, so do not rely on their contents after an error."

选择将唤醒因为:

       1)read/write availability       
2)select error
3)descriptoris closed.

但是,如果没有可用数据并且select仍在超时,我们如何从另一个线程唤醒select()?

[更新]
伪代码

          // Thread blocks on Select
void *SocketReadThread(void *param){
...
while(!(ReadThread*)param->ExitThread()) {
struct timeval timeout;
timeout.tv_sec = 60; //one minute
timeout.tv_usec = 0;

fd_set rds;
FD_ZERO(&rds);
FD_SET(sockfd, &rds)'

//actually, the first parameter of select() is
//ignored on windows, though on linux this parameter
//should be (maximum socket value + 1)
int ret = select(sockfd + 1, &rds, NULL, NULL, &timeout );
//handle the result
//might break from here

}
return NULL;
}

//main Thread
int main(){
//create the SocketReadThread
ReaderThread* rthread = new ReaderThread;
pthread_create(&pthreadid, NULL, SocketReaderThread,
NULL, (void*)rthread);

// do lots of things here
............................

//now main thread wants to exit SocketReaderThread
//it sets the internal state of ReadThread as true
rthread->SetExitFlag(true);
//but how to wake up select ??????????????????
//if SocketReaderThread currently blocks on select
}

[更新]
1)@trojanfoe提供了一种方法来实现,他的方法将socket数据(可能是脏数据或退出消息数据)写入wakeup select。我将进行测试并在那里更新结果。
2) 另外要提的是,关闭套接字并不能保证唤醒选择函数调用,请参阅 this post .

[更新2]
经过多次测试,这里有一些关于唤醒选择的事实:
1) 如果 select 监视的套接字被另一个应用程序关闭,则 select() 调用会立即醒来。此后,读取或写入套接字将获得返回值 0,errno = 0
2) 如果 select 监视的套接字被同一应用程序的另一个线程关闭,如果没有数据可读或可写,则 select() 直到超时才会唤醒。选择超时后,进行读/写操作会导致错误 errno = EBADF(因为socket在超时期间已经被另一个线程关闭了)

最佳答案

我使用基于 pipe() 的事件对象:

IoEvent.h:

#pragma once

class IoEvent {
protected:
int m_pipe[2];
bool m_ownsFDs;

public:
IoEvent(); // Creates a user event
IoEvent(int fd); // Create a file event

IoEvent(const IoEvent &other);

virtual ~IoEvent();

/**
* Set the event to signalled state.
*/
void set();

/**
* Reset the event from signalled state.
*/
void reset();

inline int fd() const {
return m_pipe[0];
}
};

IoEvent.cpp:

#include "IoEvent.h"
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>

using namespace std;

IoEvent::IoEvent() :
m_ownsFDs(true) {
if (pipe(m_pipe) < 0)
throw MyException("Failed to create pipe: %s (%d)", strerror(errno), errno);

if (fcntl(m_pipe[0], F_SETFL, O_NONBLOCK) < 0)
throw MyException("Failed to set pipe non-blocking mode: %s (%d)", strerror(errno), errno);
}

IoEvent::IoEvent(int fd) :
m_ownsFDs(false) {
m_pipe[0] = fd;
m_pipe[1] = -1;
}

IoEvent::IoEvent(const IoEvent &other) {
m_pipe[0] = other.m_pipe[0];
m_pipe[1] = other.m_pipe[1];
m_ownsFDs = false;
}

IoEvent::~IoEvent() {
if (m_pipe[0] >= 0) {
if (m_ownsFDs)
close(m_pipe[0]);

m_pipe[0] = -1;
}

if (m_pipe[1] >= 0) {
if (m_ownsFDs)
close(m_pipe[1]);

m_pipe[1] = -1;
}
}

void IoEvent::set() {
if (m_ownsFDs)
write(m_pipe[1], "x", 1);
}

void IoEvent::reset() {
if (m_ownsFDs) {
uint8_t buf;

while (read(m_pipe[0], &buf, 1) == 1)
;
}
}

您可以放弃 m_ownsFDs 成员;我什至不确定我是否会再使用它。

关于c++ - 如何在超时内从另一个线程唤醒 select(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17426186/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com