// Copyright (C) 2006 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #include <sstream> #include <string> #include <cstdlib> #include <ctime> #include <dlib/misc_api.h> #include <dlib/threads.h> #include "tester.h" namespace { using namespace test; using namespace dlib; using namespace std; logger dlog("test.threads"); void test_async() { #if __cplusplus >= 201103 print_spinner(); auto v1 = dlib::async([]() { dlib::sleep(500); return 1; }).share(); auto v2 = dlib::async([v1]() { dlib::sleep(400); return v1.get()+1; }).share(); auto v3 = dlib::async([v2](int a) { dlib::sleep(300); return v2.get()+a; },2).share(); auto v4 = dlib::async([v3]() { dlib::sleep(200); return v3.get()+1; }); DLIB_TEST(v4.get() == 5); print_spinner(); auto except = dlib::async([](){ dlib::sleep(300); throw error("oops"); }); bool got_exception = false; try { except.get(); } catch (error&e) { got_exception = true; DLIB_TEST(e.what() == string("oops")); } DLIB_TEST(got_exception); #endif } class threads_tester : public tester { public: threads_tester ( ) : tester ("test_threads", "Runs tests on the threads component."), sm(cm) {} thread_specific_data<int> tsd; rmutex cm; rsignaler sm; int count; bool failure; void perform_test ( ) { failure = false; print_spinner(); count = 10; if (!create_new_thread<threads_tester,&threads_tester::thread1>(*this)) failure = true; if (!create_new_thread<threads_tester,&threads_tester::thread2>(*this)) failure = true; if (!create_new_thread<threads_tester,&threads_tester::thread3>(*this)) failure = true; if (!create_new_thread<threads_tester,&threads_tester::thread4>(*this)) failure = true; if (!create_new_thread<threads_tester,&threads_tester::thread5>(*this)) failure = true; if (!create_new_thread<threads_tester,&threads_tester::thread6>(*this)) failure = true; if (!create_new_thread<threads_tester,&threads_tester::thread7>(*this)) failure = true; if (!create_new_thread<threads_tester,&threads_tester::thread8>(*this)) failure = true; if (!create_new_thread<threads_tester,&threads_tester::thread9>(*this)) failure = true; if (!create_new_thread<threads_tester,&threads_tester::thread10>(*this)) failure = true; thread(66); // this should happen in the main program thread if (is_dlib_thread()) failure = true; auto_mutex M(cm); while (count > 0 && !failure) sm.wait(); DLIB_TEST(!failure); test_async(); } void thread_end_handler ( ) { auto_mutex M(cm); --count; if (count == 0) sm.signal(); } void thread1() { thread(1); } void thread2() { thread(2); if (is_dlib_thread() == false) failure = true; } void thread3() { thread(3); } void thread4() { thread(4); } void thread5() { thread(5); } void thread6() { thread(6); } void thread7() { thread(7); } void thread8() { thread(8); } void thread9() { thread(9); } void thread10() { thread(10); } void thread ( int num ) { dlog << LTRACE << "starting thread num " << num; if (is_dlib_thread()) register_thread_end_handler(*this,&threads_tester::thread_end_handler); tsd.data() = num; for (int i = 0; i < 0x3FFFF; ++i) { if ((i&0xFFF) == 0) { print_spinner(); dlib::sleep(10); } // if this isn't equal to num then there is a problem with the thread specific data stuff if (tsd.data() != num) { auto_mutex M(cm); failure = true; sm.signal(); } } dlog << LTRACE << "ending of thread num " << num; } } a; }