linux select 多线程编程,双向通信,线程阻塞

Gary_Cui_1st 2016-07-16 03:31:09
我用select封装了一个socket_server和socket_client
在两个类有方法send,其本质就是一个queue,有send要求,往里面压

当socket线程启动时,在while(true)里负责不断的判断fd_set可读可写状态,当可读,即读出数据,当可写时,即把queue里的数据一次一次的send出去。

-----------------小小分割线---------
其测试使用方法为:
test_server.cpp
Thread thread(socketclient);
thread.start();
socketclient.send();//send很多次,数据很多

test_server测试方法也一样
----------------分割线--------------
无论从哪一方大量发数据,另一方等待数据,都能正常接收
----------------再次分割----------
当同时从双方大量发送数据时,程序莫名其妙的就会在test.cpp里不切到socket线程里去了,我估计socket线程被阻塞了,但是跟着,也跟不到阻塞的地方,在封装的socket里,我打了大量的log,read和write都没有阻塞,select也没有阻塞,实在想不通还有其他什么地方可以阻塞了。

求救。。。
...全文
295 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
renwotao2009 2016-07-16
  • 打赏
  • 举报
回复
引用 6 楼 dayuanyuan1989 的回复:
[quote=引用 5 楼 renwotao2009 的回复:] [quote=引用 3 楼 dayuanyuan1989 的回复:] [quote=引用 1 楼 renwotao2009 的回复:] read和write都没有阻塞,这很好理解因为你使用select,只有在读写条件满足时才会调用read或write select有也没有阻塞,看你select函数设置,有超时设置吗,还是一直阻塞直到读或写条件满足 至于你为什么没有切换到你的socket线程,你看看你的队列是否为空无法发送或者队列满了无法接收等情况
不好意思啊,是write阻塞了,刚测出来[/quote]你写一次之后,判断write的返回值n,即成功写入字节数,然后重新判断wfd是否可写[/quote] 我查了2天了,总算搞定了,谢谢啦,看来是我对select的用法产生了误解,select的fd_set可读可写状态只能保证我们一次的可读可写状态,如果在一次判断的可读或者可写状态里多次读或者写,其本质上已经脱离select的范畴了。[/quote]恩,确实是,也帮助我深入理解了
renwotao2009 2016-07-16
  • 打赏
  • 举报
回复
引用 7 楼 dayuanyuan1989 的回复:
[quote=引用 5 楼 renwotao2009 的回复:] [quote=引用 3 楼 dayuanyuan1989 的回复:] [quote=引用 1 楼 renwotao2009 的回复:] read和write都没有阻塞,这很好理解因为你使用select,只有在读写条件满足时才会调用read或write select有也没有阻塞,看你select函数设置,有超时设置吗,还是一直阻塞直到读或写条件满足 至于你为什么没有切换到你的socket线程,你看看你的队列是否为空无法发送或者队列满了无法接收等情况
不好意思啊,是write阻塞了,刚测出来[/quote]你写一次之后,判断write的返回值n,即成功写入字节数,然后重新判断wfd是否可写[/quote] 代码改起来也非常简单,把while改成if就可以了,反正外面是个大的while(true)包着的[/quote]是的
Gary_Cui_1st 2016-07-16
  • 打赏
  • 举报
回复
引用 5 楼 renwotao2009 的回复:
[quote=引用 3 楼 dayuanyuan1989 的回复:] [quote=引用 1 楼 renwotao2009 的回复:] read和write都没有阻塞,这很好理解因为你使用select,只有在读写条件满足时才会调用read或write select有也没有阻塞,看你select函数设置,有超时设置吗,还是一直阻塞直到读或写条件满足 至于你为什么没有切换到你的socket线程,你看看你的队列是否为空无法发送或者队列满了无法接收等情况
不好意思啊,是write阻塞了,刚测出来[/quote]你写一次之后,判断write的返回值n,即成功写入字节数,然后重新判断wfd是否可写[/quote] 代码改起来也非常简单,把while改成if就可以了,反正外面是个大的while(true)包着的
Gary_Cui_1st 2016-07-16
  • 打赏
  • 举报
回复
引用 5 楼 renwotao2009 的回复:
[quote=引用 3 楼 dayuanyuan1989 的回复:] [quote=引用 1 楼 renwotao2009 的回复:] read和write都没有阻塞,这很好理解因为你使用select,只有在读写条件满足时才会调用read或write select有也没有阻塞,看你select函数设置,有超时设置吗,还是一直阻塞直到读或写条件满足 至于你为什么没有切换到你的socket线程,你看看你的队列是否为空无法发送或者队列满了无法接收等情况
不好意思啊,是write阻塞了,刚测出来[/quote]你写一次之后,判断write的返回值n,即成功写入字节数,然后重新判断wfd是否可写[/quote] 我查了2天了,总算搞定了,谢谢啦,看来是我对select的用法产生了误解,select的fd_set可读可写状态只能保证我们一次的可读可写状态,如果在一次判断的可读或者可写状态里多次读或者写,其本质上已经脱离select的范畴了。
renwotao2009 2016-07-16
  • 打赏
  • 举报
回复
引用 3 楼 dayuanyuan1989 的回复:
[quote=引用 1 楼 renwotao2009 的回复:] read和write都没有阻塞,这很好理解因为你使用select,只有在读写条件满足时才会调用read或write select有也没有阻塞,看你select函数设置,有超时设置吗,还是一直阻塞直到读或写条件满足 至于你为什么没有切换到你的socket线程,你看看你的队列是否为空无法发送或者队列满了无法接收等情况
不好意思啊,是write阻塞了,刚测出来[/quote]你写一次之后,判断write的返回值n,即成功写入字节数,然后重新判断wfd是否可写
Gary_Cui_1st 2016-07-16
  • 打赏
  • 举报
回复
引用 1 楼 renwotao2009 的回复:
read和write都没有阻塞,这很好理解因为你使用select,只有在读写条件满足时才会调用read或write select有也没有阻塞,看你select函数设置,有超时设置吗,还是一直阻塞直到读或写条件满足 至于你为什么没有切换到你的socket线程,你看看你的队列是否为空无法发送或者队列满了无法接收等情况
没有超时处理
Gary_Cui_1st 2016-07-16
  • 打赏
  • 举报
回复
引用 1 楼 renwotao2009 的回复:
read和write都没有阻塞,这很好理解因为你使用select,只有在读写条件满足时才会调用read或write select有也没有阻塞,看你select函数设置,有超时设置吗,还是一直阻塞直到读或写条件满足 至于你为什么没有切换到你的socket线程,你看看你的队列是否为空无法发送或者队列满了无法接收等情况
不好意思啊,是write阻塞了,刚测出来
Gary_Cui_1st 2016-07-16
  • 打赏
  • 举报
回复
找到原因了,是两边select状态都可写,同时写,阻塞在两边同时写的状态。

我还搜了socket的write是否会引起阻塞,就没搜到出结果,没想到真的阻塞在write了,真是奇怪啊,既然select给出的是可写状态,为什么我写不了呢?


if(FD_ISSET(clientSocket[i].socketFd, pWset)) {
m_pAsynMutex->lock();

bool writeChk = false;
while (!m_clientSenderDataQueues[i].empty())
{
writeChk = true;
ByteArray data = m_clientSenderDataQueues[i].front();
printf("++++++start write...\n");
int writelen = write(clientSocket[i].socketFd, data.data(), data.length());
printf("-------end write...\n");
m_clientSenderDataQueues[i].pop();
if( writelen < 0 ) {
writeChk = false;
DEBUGERR("write error!");
close(clientSocket[i].socketFd);
FD_CLR(clientSocket[i].socketFd, pAllset);
restSocketInfo(clientSocket+i);
SocketIoHelper::clearQueue(m_clientSenderDataQueues[i]);
m_transferFileTasks[i].hasTask = false;
break;
}
if( writelen == 0 ) {
DEBUGWARN("writed length is zero!");
}

SocketIoHelper::log(LOG_DEBUG, "data length = %d, writed length = %d", data.length(), writelen);
}

m_pAsynMutex->unlock();

printf("send data queue is empty ? %s\n",m_clientSenderDataQueues[i].empty()?"true":"false");

if(!writeChk) {
continue;
}
}
}

不知道是否是我while循环的关系,一次性写得太多了?我写的处理是,当判断到fd_set可写,我就把所有需要写的数据,一次性全部写进去。



renwotao2009 2016-07-16
  • 打赏
  • 举报
回复
read和write都没有阻塞,这很好理解因为你使用select,只有在读写条件满足时才会调用read或write select有也没有阻塞,看你select函数设置,有超时设置吗,还是一直阻塞直到读或写条件满足 至于你为什么没有切换到你的socket线程,你看看你的队列是否为空无法发送或者队列满了无法接收等情况

65,207

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧