TEST(Parallel_Test, Future_Test) { reset_counters(); TestCls* values = new TestCls[DEFAULT_PARALLEL_THREAD_COUNT]; for (unsigned x = 0; x < DEFAULT_PARALLEL_THREAD_COUNT; ++x) values[x] = x; Future future; parallel.process(values, &TestCls::operator*=, DEFAULT_PARALLEL_THREAD_COUNT, 0, &future, 2); ASSERT_EQ(DEFAULT_PARALLEL_THREAD_COUNT, future.worker_count); future.wait(); ASSERT_EQ(future.finished_count, future.worker_count); delete[] values; }
TEST(Parallel_Test, Process_Object_Test_Large) { reset_counters(); TestCls* values = new TestCls[DEFAULT_PARALLEL_THREAD_COUNT + 1]; for (unsigned x = 0; x < DEFAULT_PARALLEL_THREAD_COUNT + 1; ++x) values[x] = x; Future future; parallel.process(values, &TestCls::operator*=, DEFAULT_PARALLEL_THREAD_COUNT + 1, 0, &future, 2); future.wait(); for (unsigned x = 0; x < DEFAULT_PARALLEL_THREAD_COUNT + 1; ++x) ASSERT_EQ(x * 2, values[x].value()); delete[] values; }
TEST(Parallel_Test, Batch_Test) { reset_counters(); std::atomic<unsigned> atom = 0; Future future; for (unsigned x = 0; x < BATCH_TEST_COUNT; ++x) { parallel.batch(testFunction, nullptr, &atom); } parallel.batch(testFunction, &future, &atom); future.wait(); while(!parallel.isQueueEmpty()){} ASSERT_EQ(atom.load(), BATCH_TEST_COUNT + 1); }
TEST(Parallel_Test, Process_Object_Test_Equal) { reset_counters(); TestCls* values = new TestCls[DEFAULT_PARALLEL_THREAD_COUNT]; for (unsigned x = 0; x < DEFAULT_PARALLEL_THREAD_COUNT; ++x) values[x] = x; Future future; parallel.process(values, &TestCls::operator*=, DEFAULT_PARALLEL_THREAD_COUNT, 0, &future, 2); future.wait(); ASSERT_EQ(DEFAULT_PARALLEL_THREAD_COUNT, multiplication_assignment); for (unsigned x = 0; x < DEFAULT_PARALLEL_THREAD_COUNT; ++x) ASSERT_EQ(x * 2, values[x].value()); delete[] values; }
TEST(Wait, waitWithDuration) { { Promise<int> p; Future<int> f = p.getFuture(); f.wait(milliseconds(1)); EXPECT_FALSE(f.isReady()); p.setValue(1); EXPECT_TRUE(f.isReady()); } { Promise<int> p; Future<int> f = p.getFuture(); p.setValue(1); f.wait(milliseconds(1)); EXPECT_TRUE(f.isReady()); } { vector<Future<bool>> v_fb; v_fb.push_back(makeFuture(true)); v_fb.push_back(makeFuture(false)); auto f = collectAll(v_fb); f.wait(milliseconds(1)); EXPECT_TRUE(f.isReady()); EXPECT_EQ(2, f.value().size()); } { vector<Future<bool>> v_fb; Promise<bool> p1; Promise<bool> p2; v_fb.push_back(p1.getFuture()); v_fb.push_back(p2.getFuture()); auto f = collectAll(v_fb); f.wait(milliseconds(1)); EXPECT_FALSE(f.isReady()); p1.setValue(true); EXPECT_FALSE(f.isReady()); p2.setValue(true); EXPECT_TRUE(f.isReady()); } { auto f = makeFuture().wait(milliseconds(1)); EXPECT_TRUE(f.isReady()); } { Promise<Unit> p; auto start = std::chrono::steady_clock::now(); auto f = p.getFuture().wait(milliseconds(100)); auto elapsed = std::chrono::steady_clock::now() - start; EXPECT_GE(elapsed, milliseconds(100)); EXPECT_FALSE(f.isReady()); p.setValue(); EXPECT_TRUE(f.isReady()); } { // Try to trigger the race where the resultant Future is not yet complete // even if we didn't hit the timeout, and make sure we deal with it properly Promise<Unit> p; folly::Baton<> b; auto t = std::thread([&]{ b.post(); /* sleep override */ std::this_thread::sleep_for(milliseconds(100)); p.setValue(); }); b.wait(); auto f = p.getFuture().wait(std::chrono::seconds(3600)); EXPECT_TRUE(f.isReady()); t.join(); } }
static void wait(Future& f, int n) { f.wait(n); }
// The primary thread function, which issues calls through the secondary thread void rundemos() { // Create an event for which our second thread will wait hExternalEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // Create the secondary thread DWORD dwThreadId; HANDLE hThread = CreateThread(NULL, 0, demoThread, NULL, 0, &dwThreadId); // Obtain a scheduler instance, through which we can make cross thread calls CallScheduler<APCPickupPolicy>* scheduler = CallScheduler<APCPickupPolicy>::getInstance(); // Do a first cross thread call, to a function returning a string try { string dataString = scheduler->syncCall<string, ExceptionTypes<std::exception>>(dwThreadId, boost::bind(demoFunction, 'a'), INFINITE); cout << "demoFunction returned: " << dataString << endl; } catch(CallTimeoutException&) { cout << "Call timeout." << endl; } catch(CallSchedulingFailedException&) { cout << "Call scheduling failed -- Probably a broken pickup policy." << endl; } catch(std::exception& e) { cout << "The scheduled call threw a std exception: " << e.what() << endl; } // Do a second cross thread call, to a function returning nothing try { // Expect a std::exception or DemoException scheduler->syncCall<void, ExceptionTypes<std::exception, DemoException>>(dwThreadId, boost::bind(demoVoidFunction, 'a'), 500); } catch(CallTimeoutException&) { cout << "Call timeout" << endl; } catch(CallSchedulingFailedException&) { cout << "Call scheduling failed -- Probably a broken pickup policy." << endl; } catch(std::exception& e) { cout << "demoVoidFunction threw a std exception: " << e.what() << endl; } catch(DemoException&) { cout << "demoVoidFunction threw a DemoException" << endl; } // Do a third cross thread call, to a function returning an int try { // Expect a std::exception or DemoException int demoInt = scheduler->syncCall<int, ExceptionTypes<std::exception, DemoException>>(dwThreadId, boost::bind(demoIntFunction, '!'), 500); cout << "demoIntFunction returned: " << demoInt << endl; } catch(CallTimeoutException&) { cout << "Call timeout" << endl; } catch(CallSchedulingFailedException&) { cout << "Call scheduling failed -- Probably a broken pickup policy." << endl; } catch(std::exception& e) { cout << "demoIntFunction threw a std exception: " << e.what() << endl; } catch(DemoException&) { cout << "demoIntFunction threw a DemoException" << endl; } // Do a fourth cross thread call, to a function returning an int try { boost::function<int()> f = boost::bind(demoIntFunctionDelayed, '!'); Future<int> futureDemoInt = scheduler->asyncCall<ExceptionTypes<DemoException, std::exception>>(dwThreadId, f); //Future<int> futureDemoInt2 = scheduler->asyncCall<ExceptionTypes<DemoException, std::exception>>(dwThreadId, boost::bind(demoIntFunctionDelayed, '!')); Future<void> futureDemoInt3 = scheduler->asyncCall<void>(dwThreadId, boost::bind(demoIntFunctionDelayed, '?')); Future<int> futureDemoInt4 = scheduler->asyncCall<int>(dwThreadId, boost::bind(demoIntFunctionDelayed, '!')); Future<int> futureDemoInt5 = scheduler->asyncCall<int, ExceptionTypes<DemoException>>(dwThreadId, boost::bind(demoIntFunctionDelayed, '!')); Future<void> futureDemoInt6 = scheduler->asyncCall<void, ExceptionTypes<DemoException>>(dwThreadId, boost::bind(demoIntFunctionDelayed, '!')); Future<void> futureDemoInt7 = scheduler->asyncCall<ExceptionTypes<DemoException>, void>(dwThreadId, boost::bind(demoIntFunctionDelayed, '!')); Future<int> futureDemoInt8 = scheduler->asyncCall<ExceptionTypes<DemoException>, int>(dwThreadId, boost::bind(demoIntFunctionDelayed, '!')); while(futureDemoInt.wait(10) == ASYNCH_CALL_PENDING) { cout << "Still waiting ..." << endl; } cout << "demoIntFunctionDelayed returned: " << futureDemoInt.getValue() << endl; } catch(CallSchedulingFailedException&) { cout << "Call scheduling failed -- Probably a broken pickup policy." << endl; } // Cleanup SetEvent(hExternalEvent); WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); CloseHandle(hExternalEvent); }