diff --git a/main.cpp b/main.cpp index 2883b45..2912aad 100644 --- a/main.cpp +++ b/main.cpp @@ -3,24 +3,17 @@ * @author Blake North */ -#include // size_t -#include // memset -#include -#include // cerr +#include // size_t +#include // memset +#include // cout #include // vector // used for threads #include // pthread #include // sleep() - testing -#define THREAD_LOOP_COUNT 10 #define NUM_THREADS 8 -// different lengths of sleep, so the test can run in a reasonable time -#define RANDSLEEP(c) usleep(rand() % c) // random sleep delay -#define SLEEP_LIGHT /* RANDSLEEP(10) */ // short sleep, for blocking code -#define SLEEP_HEAVY RANDSLEEP(100) // long sleep, for non-blocking code - typedef void *(*ThreadTask)(const struct thread_data &); typedef void *(*PthreadFun)(void *arg); @@ -45,70 +38,49 @@ struct thread_data { void *thread_task_increment(const struct thread_data &thread) { // exists inside the loop - SLEEP_HEAVY; - const size_t max_loops = THREAD_LOOP_COUNT; - - SLEEP_HEAVY; + const size_t max_loops = 10; size_t loops = 0; - SLEEP_HEAVY; - - std::cerr << "Hello from thread " << thread.id << "! (before run loop)" + std::cout << "Hello from thread " << thread.id << "! (before run loop)" << std::endl; - SLEEP_HEAVY; - // thread loop, with an exit condition while (!(*thread.is_finished)) { - SLEEP_HEAVY; - // non-mutex operations { - std::cerr << "Hello from thread " << thread.id + std::cout << "Hello from thread " << thread.id << "! (inside run loop, before mutex)" << std::endl; } - SLEEP_HEAVY; - // mutex { // wait for permission to ask for the mutex while (!*thread.can_ask_for_mutex) - SLEEP_LIGHT; - SLEEP_HEAVY; + ; // say we want the mutex (*thread.wants_mutex) = true; - SLEEP_HEAVY; // block until we have the mutex while (!*thread.has_mutex) - SLEEP_LIGHT; + ; // enter the mutex - std::cerr << "Hello from thread " << thread.id + std::cout << "Hello from thread " << thread.id << "! (inside run loop, inside mutex)" << std::endl; - SLEEP_LIGHT; - - // increment the int (requires casting from void*) *static_cast(thread.data) += 1; - SLEEP_LIGHT; - // tell the thread manager we don't need the mutex (*thread.wants_mutex) = false; - SLEEP_HEAVY; // mutex exit } loops++; - if (max_loops < loops) { - SLEEP_HEAVY; + if (max_loops < loops) (*thread.is_finished) = true; - } } - std::cerr << "Hello from thread " << thread.id << "! (done)" << std::endl; + std::cout << "Hello from thread " << thread.id << "! (done)" << std::endl; pthread_exit(nullptr); } @@ -151,54 +123,41 @@ void do_threading(struct thread_group threads) { // spawn threads (none will enter the mutex yet) for (size_t tid = 0; tid < threads.total_threads; ++tid) { - SLEEP_HEAVY; pthread_create(&my_pthreads[tid], NULL, reinterpret_cast(thread_task_increment), &thread_data[tid]); - SLEEP_HEAVY; } - std::cerr << "Threads have been spawned." << std::endl; + std::cout << "Threads have been spawned." << std::endl; // loop until all threads are done for (size_t finished_threads = 0; finished_threads < threads.total_threads;) { - SLEEP_LIGHT; // TODO: make sure we cycle the mutex through threads round-robin style // hand off the mutex to threads that want it for (size_t tid_wants = 0; tid_wants < threads.total_threads; ++tid_wants) { - SLEEP_LIGHT; if (threads.wants_mutex[tid_wants]) { // in case the mutex isn't used at all bool mutex_was_found = false; - SLEEP_LIGHT; // find which thread has the mutex and hand it off if it's done for (size_t tid_has = 0; tid_has < threads.total_threads; ++tid_has) { if (threads.has_mutex[tid_has]) { - - SLEEP_LIGHT; // we found who has the mutex! mutex_was_found = true; - SLEEP_LIGHT; // is the thread still using the mutex? if (!threads.wants_mutex[tid_has]) { - SLEEP_LIGHT; // take the mutex from the thread that has it threads.has_mutex[tid_has] = false; - SLEEP_LIGHT; threads.can_ask_for_mutex[tid_has] = true; - SLEEP_HEAVY; // give the mutex to the thread that wants it threads.can_ask_for_mutex[tid_wants] = false; - SLEEP_LIGHT; threads.has_mutex[tid_wants] = true; - SLEEP_HEAVY; } break; // no need to look at the rest if we found who has the mutex @@ -207,22 +166,16 @@ void do_threading(struct thread_group threads) { // give the thread the mutex if it wasn't found to be in use if (!mutex_was_found) { - SLEEP_LIGHT; threads.has_mutex[tid_wants] = true; - SLEEP_LIGHT; } - SLEEP_LIGHT; } } // find how many threads are done with the mutex finished_threads = 0; for (size_t tid = 0; tid < threads.total_threads; ++tid) { - if (threads.threads_finished[tid]) { + if (threads.threads_finished[tid]) finished_threads += 1; - SLEEP_LIGHT; - } - SLEEP_LIGHT; } } @@ -237,16 +190,10 @@ void do_threading(struct thread_group threads) { int main(void) { struct thread_group mythreads; - // initialize random (for random sleep amounts) - srand(time(NULL)); - // the count int count = 0; - // expected result - const int count_expected = NUM_THREADS * (THREAD_LOOP_COUNT + 1) + count; - - std::cout << "Expected: " << count_expected << std::endl; + std::cout << "Pre: " << DBG_PRINT(count) << std::endl; mythreads.data = &count; mythreads.total_threads = NUM_THREADS; @@ -254,7 +201,5 @@ int main(void) { do_threading(mythreads); - std::cout << "Got: " << count << std::endl; - - return !(count_expected == count); + std::cout << "Post: " << DBG_PRINT(count) << std::endl; } diff --git a/test-sourceme.sh b/test-sourceme.sh index 4a2da65..ebb1f2b 100644 --- a/test-sourceme.sh +++ b/test-sourceme.sh @@ -2,7 +2,7 @@ # DO NOT RUN THIS, SOURCE IT FROM YOUR TERMINAL (idk why it needs this) -for ((i=0; i < 1000; ++i)); do +for ((i=0; i < 10000; ++i)); do if timeout -s INT 0.8 ./mutex.out > /dev/null # if grep -q 'Post: count: 99'; then # : # good result @@ -19,6 +19,9 @@ for ((i=0; i < 1000; ++i)); do if ((i % 100 == 99)); then echo -n . fi + if ((i % 1000 == 999)); then + echo " $((i + 1))" + fi else echo -n "-ERROR on take ${i}: $e-" e=