void runTryEnqDeqThread( int numThreads, int n, /*numOps*/ MPMCQueue<int, Atom>& cq, std::atomic<uint64_t>& sum, int t) { uint64_t threadSum = 0; int src = t; // received doesn't reflect any actual values, we just start with // t and increment by numThreads to get the rounding of termination // correct if numThreads doesn't evenly divide numOps int received = t; while (src < n || received < n) { if (src < n && cq.write(src)) { src += numThreads; } int dst; if (received < n && cq.read(dst)) { received += numThreads; threadSum += dst; } } sum += threadSum; }
void runNeverFailThread(int numThreads, int n, /*numOps*/ MPMCQueue<int, Atom, Dynamic>& cq, std::atomic<uint64_t>& sum, int t) { uint64_t threadSum = 0; for (int i = t; i < n; i += numThreads) { // enq + deq EXPECT_TRUE(cq.writeIfNotFull(i)); int dest = -1; EXPECT_TRUE(cq.readIfNotEmpty(dest)); EXPECT_TRUE(dest >= 0); threadSum += dest; } sum += threadSum; }
void runNeverFailUntilThread(int numThreads, int n, /*numOps*/ MPMCQueue<int, Atom, Dynamic>& cq, std::atomic<uint64_t>& sum, int t) { uint64_t threadSum = 0; for (int i = t; i < n; i += numThreads) { // enq + deq auto soon = Clock::now() + std::chrono::seconds(1); EXPECT_TRUE(cq.tryWriteUntil(soon, i)); int dest = -1; EXPECT_TRUE(cq.readIfNotEmpty(dest)); EXPECT_TRUE(dest >= 0); threadSum += dest; } sum += threadSum; }
TEST(MPMCQueue, queue_moving) { lc_snap(); EXPECT_EQ(lc_outstanding(), 0); { MPMCQueue<Lifecycle<std::false_type>> a(50); LIFECYCLE_STEP(NOTHING); a.blockingWrite(); LIFECYCLE_STEP(DEFAULT_CONSTRUCTOR); // move constructor MPMCQueue<Lifecycle<std::false_type>> b = std::move(a); LIFECYCLE_STEP(NOTHING); EXPECT_EQ(a.capacity(), 0); EXPECT_EQ(a.size(), 0); EXPECT_EQ(b.capacity(), 50); EXPECT_EQ(b.size(), 1); b.blockingWrite(); LIFECYCLE_STEP(DEFAULT_CONSTRUCTOR); // move operator MPMCQueue<Lifecycle<std::false_type>> c; LIFECYCLE_STEP(NOTHING); c = std::move(b); LIFECYCLE_STEP(NOTHING); EXPECT_EQ(c.capacity(), 50); EXPECT_EQ(c.size(), 2); { Lifecycle<std::false_type> dst; LIFECYCLE_STEP(DEFAULT_CONSTRUCTOR); c.blockingRead(dst); LIFECYCLE_STEP(DESTRUCTOR, MOVE_OPERATOR); { // swap MPMCQueue<Lifecycle<std::false_type>> d(10); LIFECYCLE_STEP(NOTHING); std::swap(c, d); LIFECYCLE_STEP(NOTHING); EXPECT_EQ(c.capacity(), 10); EXPECT_TRUE(c.isEmpty()); EXPECT_EQ(d.capacity(), 50); EXPECT_EQ(d.size(), 1); d.blockingRead(dst); LIFECYCLE_STEP(DESTRUCTOR, MOVE_OPERATOR); c.blockingWrite(dst); LIFECYCLE_STEP(COPY_CONSTRUCTOR); d.blockingWrite(std::move(dst)); LIFECYCLE_STEP(MOVE_CONSTRUCTOR); } // d goes out of scope LIFECYCLE_STEP(DESTRUCTOR); } // dst goes out of scope LIFECYCLE_STEP(DESTRUCTOR); } // c goes out of scope LIFECYCLE_STEP(DESTRUCTOR); }
void testTimeout(MPMCQueue<int, std::atomic, Dynamic>& q) { CHECK(q.write(1)); /* The following must not block forever */ q.tryWriteUntil( std::chrono::system_clock::now() + std::chrono::microseconds(10000), 2); }