linux c实现线程超时退出,c – 如何在另一个线程的超时内唤醒select()

该博客讨论了在多线程环境下如何通过pipe()创建的事件对象来唤醒被select()阻塞的线程。当需要结束SocketReadThread时,通过写入事件对象来触发select的唤醒,而不是依赖于数据读写或关闭套接字。此外,文中还提到了在套接字被关闭时select的行为,并提供了测试结果和解决方案。
摘要由CSDN通过智能技术生成

根据“男人选择”信息:

"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."

选择将wakup因为:

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

}

[UPDATE]

1)@trojanfoe提供了一种实现此目的的方法,他的方法将套接字数据(可能是脏数据或退出消息数据)写入唤醒选择.我将进行测试并在那里更新结果.

2)另外要提一下,关闭套接字并不能保证唤醒select函数调用,请参见this post.

[UPDATE2]

做了很多测试后,这里有一些关于唤醒选择的事实:

1)如果select监视的套接字被另一个应用程序关闭,则select()调用

会立刻醒来.此后,读取或写入套接字将使用errno = 0获得返回值0

2)如果select监视的套接字被同一应用程序的另一个线程关闭,

如果没有要读取或写入的数据,则select()将在超时之前不会唤醒.选择超时后,使用errno = EBADF进行读/写操作会导致错误

(因为套接字在超时期间已被另一个线程关闭)

解决方法:

我使用基于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

#include

#include

#include

#include

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-2,linux,tcp,multithreading,sockets

来源: https://codeday.me/bug/20190529/1177712.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值