Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

epoll_wait不会阻塞 #74

Open
lok1818 opened this issue Feb 18, 2020 · 1 comment
Open

epoll_wait不会阻塞 #74

lok1818 opened this issue Feb 18, 2020 · 1 comment

Comments

@lok1818
Copy link

lok1818 commented Feb 18, 2020

发现cross里这个epoll_wait真的不阻塞,在没完没了的返回-1,GetLastError=EINTR,也就是所有线程都在空转了,这个应该会占掉不少cpu,影响性能,怎么解决?

Net.CrossSocket.Epoll.pas里的function TEpollCrossSocket.ProcessIoEvent: Boolean;

LRet := epoll_wait(FEpollHandle, @FEventList[0], MAX_EVENT_COUNT, -1);
if (LRet < 0) then
begin
LRet := GetLastError;
// EINTR, epoll_wait 调用被系统信号打断, 可以进行重试
Exit(LRet = EINTR);
end;

@lok1818
Copy link
Author

lok1818 commented Mar 4, 2020

原因大致搞明白了,这个不是被系统信号唤醒的,是因为断点单步调试的时候唤醒的,不调试的情况下不会醒。但有一个问题是当有新连接进来要Accept的时候,会同时唤醒好多个线程。因为他们等待的是同一个epoll以及同一个ListenSocket,任何发生在上面的事件都会通知到所有线程,所以被唤醒了。解决思路有两个:
1.给每个线程创建自己的epoll对象和ListenSocket(需设置端口重用,必须在主线程中创建并listen),对于server端建议使用这个模式,可以实现多线程同时贞听,新连接进来的时候会平均分配到不同的线程上去。
2.通过信号量TSemaphore或临界区TMutex,每次只允许一个线程执行epoll_wait,对client端可以使用这个办法,也就是当一个线程执行read/write的时候,另一个线程去执行epoll_wait,同理,如果有大量read/write的时候,哪这些线程就可以去并发执行read/write了。参考代码如下:
EpoolMutex.Acquire;
while True do
begin
LRet := epoll_wait(FEpollHandle, @FEventList[0], MAX_EVENT_COUNT, cNetworkThreadIdleTime);
if (LRet < 0) then
begin
LRet := GetLastError;
if LRet = EINTR then //EINTR, epoll_wait 调用被系统信号打断, 可以进行重试
Continue
else if LRet = ETIMEDOUT then //等待超时
begin
FreeMemory(GetMemory(1)); //释放内存
Continue;
end
else
begin
sleep(1);
Continue;
end;
end
else
Break;
end;
EpoolMutex.Release;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant