Changeset: 2ccf33f2bc81 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/2ccf33f2bc81
Modified Files:
        clients/examples/C/testcondvar.c
Branch: Sep2022
Log Message:

Improve testcondvar.c test output, add some comments


diffs (200 lines):

diff --git a/clients/examples/C/testcondvar.c b/clients/examples/C/testcondvar.c
--- a/clients/examples/C/testcondvar.c
+++ b/clients/examples/C/testcondvar.c
@@ -16,7 +16,12 @@
 
 volatile int timeout = 100; // set this to 0 during interactive debugging
 
-/* global state protected by a lock: */
+/* global state protected by a lock.
+ *
+ * Every worker thread has a number of permits and a number of ticks.
+ * It sleeps on the condition variable, whenever it wakes it will
+ * try to convert one permit into a tick, that is, permit-- and tick++.
+ */
 
 MT_Lock lock = MT_LOCK_INITIALIZER(lock);
 MT_Cond condvar = MT_COND_INITIALIZER(the_condvar);
@@ -28,7 +33,15 @@ struct state {
        bool terminated;
 } states[NN] = { {0} };
 
-
+/*
+ * The main thread holds the lock so it can manipulate and verify the permits
+ * and ticks.  It uses this function to temporarily release the lock so the
+ * workers get a chance to do their work. We give them a 100ms, which should be
+ * plenty.
+ *
+ * If we cannot retake the lock after that interval we assume a worker thread
+ * has gone astray while holding the lock.
+ */
 static void
 let_run(void)
 {
@@ -36,16 +49,17 @@ let_run(void)
 
        MT_sleep_ms(100);
 
+       // try to retake the lock. Make a few attempts before giving up.
        int attempts = 0;
        while (!MT_lock_try(&lock)) {
                if (timeout > 0 && ++attempts > timeout) {
                        fprintf(stderr, "Can't get hold of the lock after %d 
attempts\n", attempts);
+                       fprintf(stderr, "If this is because you're running this 
program in a debugger,\n");
+                       fprintf(stderr, "try setting the timeout variable to 
0.\n");
                        abort();
                }
                MT_sleep_ms(10);
        }
-
-       fprintf(stderr, "\n");
 }
 
 
@@ -54,9 +68,10 @@ worker(void *arg)
 {
        struct state *st = arg;
        int id = (int)(st - &states[0]);
-       fprintf(stderr, "worker %d starting\n", id);
+       fprintf(stderr, "worker %d started, waiting to acquire lock\n", id);
 
        MT_lock_set(&lock);
+       fprintf(stderr, "worker %d acquired lock\n", id);
        while (1) {
                if (st->terminate) {
                        fprintf(stderr, "worker %d terminating\n", id);
@@ -67,7 +82,7 @@ worker(void *arg)
                        st->ticks++;
                        st->permits--;
                }
-               fprintf(stderr, "worker %d waiting\n", id);
+               fprintf(stderr, "worker %d waiting on condvar\n", id);
                MT_cond_wait(&condvar, &lock);
                fprintf(stderr, "worker %d woke up\n", id);
        }
@@ -76,16 +91,6 @@ worker(void *arg)
 }
 
 
-static void clear(void)
-{
-       for (int i = 0; i < NN; i++) {
-               struct state *st = &states[i];
-               st->permits = 0;
-               st->ticks = 0;
-       }
-}
-
-
 static void
 check_impl(int line, int expected_sum_ticks, int expected_max_ticks, int 
expected_sum_permits)
 {
@@ -101,17 +106,26 @@ check_impl(int line, int expected_sum_ti
                        max_ticks = ticks;
        }
 
+       fprintf(stderr, "On line %d: (sum_ticks, max_ticks, sum_permits) = (%d, 
%d, %d)\n",
+                       line,
+                       sum_ticks, max_ticks, sum_permits);
+
        bool good = true;
        good &= (sum_ticks == expected_sum_ticks);
-       good &= (max_ticks == expected_max_ticks);
+       if (expected_max_ticks >= 0)
+               good &= (max_ticks == expected_max_ticks);
        good &= (sum_permits == expected_sum_permits);
        if (good)
                return;
 
-       fprintf(stderr, "\nOn line %d:\n", line);
-       fprintf(stderr, "Expect sum ticks to be %d, is %d\n", 
expected_sum_ticks, sum_ticks);
-       fprintf(stderr, "Expect max ticks to be %d, is %d\n", 
expected_max_ticks, max_ticks);
-       fprintf(stderr, "Expect sum permits to be %d, is %d\n", 
expected_sum_permits, sum_permits);
+       if (expected_max_ticks >= 0) {
+               fprintf(stderr, "MISMATCH: expected (%d, %d, %d)\n",
+                       expected_sum_ticks, expected_max_ticks, 
expected_sum_permits);
+       } else {
+               fprintf(stderr, "MISMATCH: expected (%d, ?, %d)\n",
+                       expected_sum_ticks, expected_sum_permits);
+       }
+
        for (int i = 0; i < NN; i++) {
                fprintf(stderr, "worker %d: ticks=%d permits=%d\n", i, 
states[i].ticks, states[i].permits);
        }
@@ -125,30 +139,54 @@ main(void)
 {
        MT_thread_init();
 
+       // All code in this function runs while we hold the lock.
+       // From time to time we call let_run() to allow the worker threads to 
obtain it.
        MT_lock_set(&lock);
+
+       fprintf(stderr, "-- Initially, everything is zero\n");
        check(0, 0, 0);
 
+       fprintf(stderr, "\n-- Starting the worker threads\n");
        for (int i = 0; i < NN; i++) {
                struct state *st = &states[i];
                char name[MT_NAME_LEN];
                snprintf(name, sizeof(name), "worker%d", i);
                MT_create_thread(&st->id, worker, st, MT_THR_JOINABLE, name);
        }
-       check(0, 0, 0);
+       MT_sleep_ms(100);
 
+       fprintf(stderr, "\n-- Now allow the workers to take the lock, they 
should enter their main loop\n");
        let_run();
        check(0, 0, 0);
 
-       // give them all a permit and broadcast on the condvar. they should all 
run
+       fprintf(stderr, "\n-- All threads get a permit but nothing happens 
because we haven't touched the condvar\n");
        for (int i = 0; i < NN; i++)
                states[i].permits = 1;
        let_run();
-       // haven't notified them yet:
-       check(0, 0, 3);
+       check(0, 0, NN);
+
+       fprintf(stderr, "\n-- Now we broadcast on the condvar. All should 
wake\n");
        MT_cond_broadcast(&condvar);
        let_run();
-       check(3, 1, 0);
+       check(NN, 1, 0);
+
+       fprintf(stderr, "\n-- Now we give each of them %d permits\n", NN);
+       for (int i = 0; i < NN; i++) {
+               states[i].ticks = 0;
+               states[i].permits = NN;
+       }
+       check(0, 0, NN * NN);
 
+       // Note: counting from 1 instead of 0
+       for (int i = 1; i <= NN; i++) {
+               fprintf(stderr, "\n-- [%d] Signal one, don't know which one it 
will be\n", i);
+               MT_cond_signal(&condvar);
+               let_run();
+               check(i, -1, NN * NN - i);
+       }
+
+
+       fprintf(stderr, "\n-- Telling them all to quit\n");
        for (int i = 0; i < NN; i++) {
                states[i].terminate = true;
        }
@@ -156,12 +194,11 @@ main(void)
        let_run();
 
        for (int i = 0; i < NN; i++) {
-               fprintf(stderr, "joining worker %d\n", i);
+               fprintf(stderr, "-- Joining worker %d\n", i);
                MT_join_thread(states[i].id);
+               fprintf(stderr, "-- Joined worker %d\n", i);
        }
-       fprintf(stderr, "joined all, exiting\n");
+       fprintf(stderr, "\n-- Joined all, exiting\n");
 
-       (void)worker;
-       (void)let_run;
        return 0;
 }
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to