Skip to content

Commit 4d0f72e

Browse files
Wait for loop to exit in EventLoop destructor. (#198)
1 parent 3ddca84 commit 4d0f72e

File tree

2 files changed

+37
-12
lines changed

2 files changed

+37
-12
lines changed

trantor/net/EventLoop.cc

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
#include <thread>
2626
#include <assert.h>
2727
#ifdef _WIN32
28+
#include <windows.h>
2829
#include <io.h>
30+
#include <synchapi.h>
2931
using ssize_t = long long;
3032
#else
3133
#include <poll.h>
@@ -101,7 +103,7 @@ EventLoop::EventLoop()
101103
void EventLoop::resetTimerQueue()
102104
{
103105
assertInLoopThread();
104-
assert(!looping_);
106+
assert(!looping_.load(std::memory_order_acquire));
105107
timerQueue_->reset();
106108
}
107109
#endif
@@ -111,8 +113,29 @@ void EventLoop::resetAfterFork()
111113
}
112114
EventLoop::~EventLoop()
113115
{
116+
#ifdef _WIN32
117+
DWORD delay = 1; /* 1 msec */
118+
#else
119+
struct timespec delay = {0, 1000000}; /* 1 msec */
120+
#endif
121+
114122
quit();
115-
assert(!looping_);
123+
124+
// Spin waiting for the loop to exit because
125+
// this may take some time to complete. We
126+
// assume the loop thread will *always* exit.
127+
// If this cannot be guaranteed then one option
128+
// might be to abort waiting and
129+
// assert(!looping_) after some delay;
130+
while (looping_.load(std::memory_order_acquire))
131+
{
132+
#ifdef _WIN32
133+
Sleep(delay);
134+
#else
135+
nanosleep(&delay, nullptr);
136+
#endif
137+
}
138+
116139
t_loopInThisThread = nullptr;
117140
#ifdef __linux__
118141
close(wakeupFd_);
@@ -140,7 +163,7 @@ void EventLoop::removeChannel(Channel *channel)
140163
}
141164
void EventLoop::quit()
142165
{
143-
quit_ = true;
166+
quit_.store(true, std::memory_order_release);
144167

145168
Func f;
146169
while (funcsOnQuit_.dequeue(f))
@@ -160,10 +183,10 @@ void EventLoop::loop()
160183
{
161184
assert(!looping_);
162185
assertInLoopThread();
163-
looping_ = true;
164-
quit_ = false;
186+
looping_.store(true, std::memory_order_release);
187+
quit_.store(false, std::memory_order_release);
165188

166-
while (!quit_)
189+
while (!quit_.load(std::memory_order_acquire))
167190
{
168191
activeChannels_.clear();
169192
#ifdef __linux__
@@ -187,7 +210,7 @@ void EventLoop::loop()
187210
// std::cout << "looping" << endl;
188211
doRunInLoopFuncs();
189212
}
190-
looping_ = false;
213+
looping_.store(false, std::memory_order_release);
191214
}
192215
void EventLoop::abortNotInLoopThread()
193216
{
@@ -198,15 +221,15 @@ void EventLoop::abortNotInLoopThread()
198221
void EventLoop::queueInLoop(const Func &cb)
199222
{
200223
funcs_.enqueue(cb);
201-
if (!isInLoopThread() || !looping_)
224+
if (!isInLoopThread() || !looping_.load(std::memory_order_acquire))
202225
{
203226
wakeup();
204227
}
205228
}
206229
void EventLoop::queueInLoop(Func &&cb)
207230
{
208231
funcs_.enqueue(std::move(cb));
209-
if (!isInLoopThread() || !looping_)
232+
if (!isInLoopThread() || !looping_.load(std::memory_order_acquire))
210233
{
211234
wakeup();
212235
}

trantor/net/EventLoop.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <functional>
2929
#include <chrono>
3030
#include <limits>
31+
#include <atomic>
3132

3233
namespace trantor
3334
{
@@ -270,7 +271,8 @@ class TRANTOR_EXPORT EventLoop : NonCopyable
270271
*/
271272
bool isRunning()
272273
{
273-
return looping_ && (!quit_);
274+
return looping_.load(std::memory_order_acquire) &&
275+
(!quit_.load(std::memory_order_acquire));
274276
}
275277

276278
/**
@@ -297,9 +299,9 @@ class TRANTOR_EXPORT EventLoop : NonCopyable
297299
void abortNotInLoopThread();
298300
void wakeup();
299301
void wakeupRead();
300-
bool looping_;
302+
std::atomic<bool> looping_;
301303
std::thread::id threadId_;
302-
bool quit_;
304+
std::atomic<bool> quit_;
303305
std::unique_ptr<Poller> poller_;
304306

305307
ChannelList activeChannels_;

0 commit comments

Comments
 (0)