threadExample.cpp

Example showing ARIA's cross-platform threading tools.

ARIA provides some tools for writing multithreaded programs. These are abstractions of the threading library provided by the native operating system.

The three main tools are:

This example program shows the use of all three, with two threads interacting: the program's main thread of execution, and a new thread created using ArASyncTask. An ArMutex object is used to keep use of some shared data safe, and then the use of ArCondition is shown.

Threading can be error-prone, since any (perhaps subconcious) assumptions you have about the linear execution of code may not apply to simultaneous threads. Furthermore, different computers will execute multithreaded code in different ways (especially if they have different numbers of CPUs). ARIA's threading tools can help make multiple threads work, and help make multithreaded code portable, but you must always think carefully about how code might execute (including error conditions!) to avoid deadlocks and race conditions.

00001 /*
00002 MobileRobots Advanced Robotics Interface for Applications (ARIA)
00003 Copyright (C) 2004,2005 ActivMedia Robotics LLC
00004 Copyright (C) 2006 MobileRobots, Inc.
00005 
00006      This program is free software; you can redistribute it and/or modify
00007      it under the terms of the GNU General Public License as published by
00008      the Free Software Foundation; either version 2 of the License, or
00009      (at your option) any later version.
00010 
00011      This program is distributed in the hope that it will be useful,
00012      but WITHOUT ANY WARRANTY; without even the implied warranty of
00013      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014      GNU General Public License for more details.
00015 
00016      You should have received a copy of the GNU General Public License
00017      along with this program; if not, write to the Free Software
00018      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 If you wish to redistribute ARIA under different terms, contact 
00021 MobileRobots for information about a commercial version of ARIA at 
00022 robots@mobilerobots.com or 
00023 MobileRobots Inc, 19 Columbia Drive, Amherst, NH 03031; 800-639-9481
00024 */
00025 
00026 
00057 #include "Aria.h"
00058 
00059 
00060 /* A subclass of ArASyncTask, to contain a method that runs in a new thread */
00061 class ExampleThread : public ArASyncTask
00062 {
00063   ArCondition myCondition;
00064   ArMutex myMutex;
00065   int myCounter;
00066 public:
00067 
00068   /* Construtor. Initialize counter. */
00069   ExampleThread() : myCounter(0)
00070   {
00071   }
00072 
00073 
00074   /* This method is called in the new thread when launched. The void* parameter
00075    * and return value are platform implementation-specific an can be ignored.
00076    * This method will run in a loop, incrementing the counter each second, but 
00077    * locking the mutex to prevent conflicting access by other threads. 
00078    * If it reaches a value divisible by ten, signal our condition variable. If
00079    * it is set to -1, exit the thread.
00080    */
00081   void* runThread(void*) 
00082   {
00083     // Run until the thread is requested to end by another thread.
00084     while(this->getRunningWithLock())
00085     {
00086       myMutex.lock();
00087 
00088       // Increment the counter. 
00089       myCounter++;
00090       ArLog::log(ArLog::Normal, "Example thread: incremented counter to %d.", myCounter);
00091 
00092       // If it's now divisible by 10, signal the condition variable.
00093       if(myCounter % 10 == 0)
00094       {
00095         ArLog::log(ArLog::Normal, "Example thread: Signalling condition.");
00096         myCondition.signal();
00097       }
00098 
00099       // Unlock, then sleep.  We unlock before the sleep, so that while
00100       // we are sleeping, other threads that try to lock the mutex won't
00101       // be blocked until this thread is done sleeping.
00102       myMutex.unlock();
00103       ArUtil::sleep(1000);
00104     }
00105 
00106     ArLog::log(ArLog::Normal, "Example thread: requested stop running, ending thread.");
00107     return NULL;
00108   }
00109 
00110   /* Other threads can call this to wait for a condition eventually
00111    * signalled by this thread.
00112    */
00113   void waitOnCondition()
00114   {
00115     myCondition.wait();
00116   }
00117 
00118   /* Get the counter. Not threadsafe, you must lock the mutex during access. */
00119   int getCounter() { return myCounter; }
00120 
00121   /* Set the countner. Not threadsafe, you must lock the mutex during access. */
00122   void setCounter(int ctr) { myCounter = ctr; }
00123 
00124   /* Lock the mutex object.  */
00125   void lockMutex() { myMutex.lock(); }
00126 
00127   /* Unlock the mutex object. */
00128   void unlockMutex() { myMutex.unlock(); }
00129 
00130 };
00131 
00132 int main()
00133 {
00134   Aria::init();
00135 
00136   ExampleThread exampleThread;
00137 
00138   /* Launch the new thread in the background. This thread (of main()) continues
00139    * immediately. */
00140   ArLog::log(ArLog::Normal, "Main thread: Running new example thread ...");
00141   exampleThread.runAsync();
00142 
00143   /* Loop, reading the value contained in the ExampleThread object.
00144    * We will also use ArUtil::sleep() to make this thread sleep each iteration,
00145    * instead of running as fast as possible and potentially preventing other
00146    * threads from access to the mutex and the shared counter.
00147    * When the counter reaches 10, break out of the loop and then wait on the
00148    * condition variable.
00149    */
00150   while(true)
00151   {
00152     exampleThread.lockMutex();
00153     int c = exampleThread.getCounter();
00154     exampleThread.unlockMutex(); // we can unlock the mutex now, since we made a copy of the counter.
00155 
00156     printf("Main thread: Counter=%d.\n", c);
00157 
00158     if(c >= 10)
00159       break;
00160 
00161     ArUtil::sleep(600);
00162   }
00163 
00164 
00165   /* This shows how to block on an ArCondition object. 
00166    * wait() will *only* return when the condition object is 
00167    * signaled by the other thread.
00168    */
00169   ArLog::log(ArLog::Normal, "Main thread: Waiting on condition object...");
00170   exampleThread.waitOnCondition();
00171 
00172   ArLog::log(ArLog::Normal, "Main thread: Condition was signaled, and execution continued. Telling the other thread to stop running.");
00173   exampleThread.stopRunning();
00174   
00175   ArLog::log(ArLog::Normal, "Main thread: Waiting for the other thread to exit, then exiting the program.");
00176   do {
00177     ArUtil::sleep(250);
00178   } while(exampleThread.getRunningWithLock());
00179 
00180   ArLog::log(ArLog::Normal, "Main thread: Exiting program.");
00181   return 0;
00182 }

Generated on Fri Dec 1 10:55:11 2006 for Aria by  doxygen 1.4.7