dlib C++ Library - threads_ex.cpp

    /*

        This is an example illustrating the use of the threading api from the
        dlib C++ Library.

        This is a very simple example.  It makes some threads and just waits for
        them to terminate.
    */

    #include <iostream>
    #include "dlib/threads.h"
    #include "dlib/misc_api.h"  // for dlib::sleep

    using namespace std;
    using namespace dlib;

    int thread_count = 10;
    mutex count_mutex; // This is a mutex we will use to guard the thread_count variable.  Note that the mutex doesn't know
                       // anything about the thread_count variable.  Only our usage of a mutex determines what it guards.
                       // In this case we are going to make sure this mutex is always locked before we touch the
                       // thread_count variable.

    signaler count_signaler(count_mutex);  // This is a signaler we will use to signal when
                                           // the thread_count variable is changed.  Note that it is
                                           // associated with the count_mutex.  This means that
                                           // when you call count_signaler.wait() it will automatically
                                           // unlock count_mutex for you.

    void thread (void*)
    {
        // just sleep for a second
        dlib::sleep(1000);

        // Now signal that this thread is ending.  First we should get a lock on the
        // count_mutex so we can safely mess with thread_count.  A convenient way to do this
        // is to use an auto_mutex object.  Its constructor takes a mutex object and locks
        // it right away, it then unlocks the mutex when the auto_mutex object is destructed.
        // Note that this happens even if an exception is thrown.  So it ensures that you
        // don't somehow quit your function without unlocking your mutex.
        auto_mutex locker(count_mutex);
        --thread_count;
        // Now we signal this change.  This will cause one thread that is currently waiting
        // on a call to count_signaler.wait() to unblock.
        count_signaler.signal();

        // At the end of this function locker goes out of scope and gets destructed, thus
        // unlocking count_mutex for us.
    }

    int main()
    {

        cout << "Create some threads" << endl;
        for (int i = 0; i < thread_count; ++i)
        {
            // Create some threads.  This 0 we are passing in here is the argument that gets
            // passed to the thread function (a void pointer) but we aren't using it in this
            // example program so i'm just using 0.
            create_new_thread(thread,0);
        }
        cout << "Done creating threads, now we wait for them to end" << endl;

        // Again we use an auto_mutex to get a lock.  We don't have to do it this way
        // but it is convenient.  Also note that we can name the auto_mutex object anything.
        auto_mutex some_random_unused_name(count_mutex);

        // Now we wait in a loop for thread_count to be 0.  Note that it is important to do this in a
        // loop because it is possible to get spurious wakeups from calls to wait() on some
        // platforms.  So this guards against that and it also makes the code easy to understand.
        while (thread_count > 0)
            count_signaler.wait(); // This puts this thread to sleep until we get a signal to look at the
                                   // thread_count variable.  It also unlocks the count_mutex before it
                                   // goes to sleep and then relocks it when it wakes back up.  Again,
                                   // note that it is possible for wait() to return even if no one signals you.
                                   // This is just weird junk you have to deal with on some platforms.  So
                                   // don't try to be clever and write code that depends on the number of
                                   // times wait() returns because it won't always work.

        cout << "All threads done, ending program" << endl;
    }