@@ -6511,18 +6511,103 @@ TEST(SocketStream, is_writable_INET) {
6511
6511
#endif // #ifndef _WIN32
6512
6512
6513
6513
TEST (TaskQueueTest, IncreaseAtomicInteger) {
6514
- static constexpr unsigned int number_of_task {1000000 };
6514
+ static constexpr unsigned int number_of_tasks {1000000 };
6515
6515
std::atomic_uint count{0 };
6516
6516
std::unique_ptr<TaskQueue> task_queue{
6517
6517
new ThreadPool{CPPHTTPLIB_THREAD_POOL_COUNT}};
6518
6518
6519
- for (unsigned int i = 0 ; i < number_of_task ; ++i) {
6520
- task_queue->enqueue (
6519
+ for (unsigned int i = 0 ; i < number_of_tasks ; ++i) {
6520
+ auto queued = task_queue->enqueue (
6521
6521
[&count] { count.fetch_add (1 , std::memory_order_relaxed); });
6522
+ EXPECT_TRUE (queued);
6523
+ }
6524
+
6525
+ EXPECT_NO_THROW (task_queue->shutdown ());
6526
+ EXPECT_EQ (number_of_tasks, count.load ());
6527
+ }
6528
+
6529
+ TEST (TaskQueueTest, IncreaseAtomicIntegerWithQueueLimit) {
6530
+ static constexpr unsigned int number_of_tasks{1000000 };
6531
+ static constexpr unsigned int qlimit{2 };
6532
+ unsigned int queued_count{0 };
6533
+ std::atomic_uint count{0 };
6534
+ std::unique_ptr<TaskQueue> task_queue{
6535
+ new ThreadPool{/* num_threads=*/ 1 , qlimit}};
6536
+
6537
+ for (unsigned int i = 0 ; i < number_of_tasks; ++i) {
6538
+ if (task_queue->enqueue (
6539
+ [&count] { count.fetch_add (1 , std::memory_order_relaxed); })) {
6540
+ queued_count++;
6541
+ }
6542
+ }
6543
+
6544
+ EXPECT_NO_THROW (task_queue->shutdown ());
6545
+ EXPECT_EQ (queued_count, count.load ());
6546
+ EXPECT_TRUE (queued_count <= number_of_tasks);
6547
+ EXPECT_TRUE (queued_count >= qlimit);
6548
+ }
6549
+
6550
+ TEST (TaskQueueTest, MaxQueuedRequests) {
6551
+ static constexpr unsigned int qlimit{3 };
6552
+ std::unique_ptr<TaskQueue> task_queue{new ThreadPool{1 , qlimit}};
6553
+ std::condition_variable sem_cv;
6554
+ std::mutex sem_mtx;
6555
+ int credits = 0 ;
6556
+ bool queued;
6557
+
6558
+ /* Fill up the queue with tasks that will block until we give them credits to
6559
+ * complete. */
6560
+ for (unsigned int n = 0 ; n <= qlimit;) {
6561
+ queued = task_queue->enqueue ([&sem_mtx, &sem_cv, &credits] {
6562
+ std::unique_lock<std::mutex> lock (sem_mtx);
6563
+ while (credits <= 0 ) {
6564
+ sem_cv.wait (lock);
6565
+ }
6566
+ /* Consume the credit and signal the test code if they are all gone. */
6567
+ if (--credits == 0 ) { sem_cv.notify_one (); }
6568
+ });
6569
+
6570
+ if (n < qlimit) {
6571
+ /* The first qlimit enqueues must succeed. */
6572
+ EXPECT_TRUE (queued);
6573
+ } else {
6574
+ /* The last one will succeed only when the worker thread
6575
+ * starts and dequeues the first blocking task. Although
6576
+ * not necessary for the correctness of this test, we sleep for
6577
+ * a short while to avoid busy waiting. */
6578
+ std::this_thread::sleep_for (std::chrono::milliseconds (10 ));
6579
+ }
6580
+ if (queued) { n++; }
6581
+ }
6582
+
6583
+ /* Further enqueues must fail since the queue is full. */
6584
+ for (auto i = 0 ; i < 4 ; i++) {
6585
+ queued = task_queue->enqueue ([] {});
6586
+ EXPECT_FALSE (queued);
6587
+ }
6588
+
6589
+ /* Give the credits to allow the previous tasks to complete. */
6590
+ {
6591
+ std::unique_lock<std::mutex> lock (sem_mtx);
6592
+ credits += qlimit + 1 ;
6593
+ }
6594
+ sem_cv.notify_all ();
6595
+
6596
+ /* Wait for all the credits to be consumed. */
6597
+ {
6598
+ std::unique_lock<std::mutex> lock (sem_mtx);
6599
+ while (credits > 0 ) {
6600
+ sem_cv.wait (lock);
6601
+ }
6602
+ }
6603
+
6604
+ /* Check that we are able again to enqueue at least qlimit tasks. */
6605
+ for (unsigned int i = 0 ; i < qlimit; i++) {
6606
+ queued = task_queue->enqueue ([] {});
6607
+ EXPECT_TRUE (queued);
6522
6608
}
6523
6609
6524
6610
EXPECT_NO_THROW (task_queue->shutdown ());
6525
- EXPECT_EQ (number_of_task, count.load ());
6526
6611
}
6527
6612
6528
6613
TEST (RedirectTest, RedirectToUrlWithQueryParameters) {
0 commit comments