Skip to content

Commit 58cffd3

Browse files
authored
std::condition_variable::notify_one/all() should be called after unlocking mutex (#1448)
* Move next job in task queue rather than copy * Notify waiting thread after unlocking mutex * Add unit test for TaskQueue * Don't use C++14 feature in test code
1 parent 8f32271 commit 58cffd3

File tree

2 files changed

+24
-4
lines changed

2 files changed

+24
-4
lines changed

httplib.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -549,8 +549,11 @@ class ThreadPool : public TaskQueue {
549549
~ThreadPool() override = default;
550550

551551
void enqueue(std::function<void()> fn) override {
552-
std::unique_lock<std::mutex> lock(mutex_);
553-
jobs_.push_back(std::move(fn));
552+
{
553+
std::unique_lock<std::mutex> lock(mutex_);
554+
jobs_.push_back(std::move(fn));
555+
}
556+
554557
cond_.notify_one();
555558
}
556559

@@ -559,9 +562,10 @@ class ThreadPool : public TaskQueue {
559562
{
560563
std::unique_lock<std::mutex> lock(mutex_);
561564
shutdown_ = true;
562-
cond_.notify_all();
563565
}
564566

567+
cond_.notify_all();
568+
565569
// Join...
566570
for (auto &t : threads_) {
567571
t.join();
@@ -583,7 +587,7 @@ class ThreadPool : public TaskQueue {
583587

584588
if (pool_.shutdown_ && pool_.jobs_.empty()) { break; }
585589

586-
fn = pool_.jobs_.front();
590+
fn = std::move(pool_.jobs_.front());
587591
pool_.jobs_.pop_front();
588592
}
589593

test/test.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <atomic>
66
#include <chrono>
77
#include <future>
8+
#include <memory>
89
#include <sstream>
910
#include <stdexcept>
1011
#include <thread>
@@ -5522,3 +5523,18 @@ TEST(SocketStream, is_writable_INET) {
55225523
ASSERT_EQ(0, close(disconnected_svr_sock));
55235524
}
55245525
#endif // #ifndef _WIN32
5526+
5527+
TEST(TaskQueueTest, IncreaseAtomicInteger) {
5528+
static constexpr unsigned int number_of_task{1000000};
5529+
std::atomic_uint count{0};
5530+
std::unique_ptr<TaskQueue> task_queue{
5531+
new ThreadPool{CPPHTTPLIB_THREAD_POOL_COUNT}};
5532+
5533+
for (unsigned int i = 0; i < number_of_task; ++i) {
5534+
task_queue->enqueue(
5535+
[&count] { count.fetch_add(1, std::memory_order_relaxed); });
5536+
}
5537+
5538+
EXPECT_NO_THROW(task_queue->shutdown());
5539+
EXPECT_EQ(number_of_task, count.load());
5540+
}

0 commit comments

Comments
 (0)