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 }
1.4.7