Threads and semaphores¶
The MARTe framework offers a portable API for the management and synchronisation of multi-threaded applications.
Note
The preferred way of using threads is through the Services interface.
Threads¶
The Threads API allows to launch named threads bounded by to a specific CPU affinity (see ProcessorType) and with a defined amount of stack memory. The thread priority class and priority level can also be changed for every individual thread.
Warning
The change of some of the thread parameters (e.g. priorities) might fail if the user does not have the appropriate operating system permissions.
...
void IncrementDecrementFunction(const void * const parameters) {
...
}
...
Threads::BeginThread(&IncrementDecrementFunction, (int64 *)i, THREADS_DEFAULT_STACKSIZE, "NamedThread", ExceptionHandler::NotHandled, 0x1);
Note
When starting a thread, if the affinity parameter is not set, the thread will be allowed to run in the default CPU set. The application default CPU set can be changed with ProcessorType::SetDefaultCPUs(...)
The framework also allows to query the number of threads and its associated properties (see ThreadInformation and Threads::GetThreadInfoCopy
).
Atomic operations¶
The Atomic API offers a set of portable functions that allow to perform atomic operations, i.e. operations that are guaranteed to be uninterruptible in a multi-threaded application environment.
...
b = Atomic::Exchange(&a, b);
...
Atomic::Increment(&a);
...
if (!Atomic::TestAndSet(&locked)) {
In particular, the Atomic::TestAndSet
functions are used to implement fast polling mutex semaphores (see below) that can be deployed in environments that do not have an operating system scheduler.
High Resolution Timer¶
The HighResolutionTimer provides a portable abstraction of a timer and allows to measure ticks with high resolution.
These ticks (see HighResolutionTimer::Counter()
) can be converted from/into time using the HighResolutionTimer::Frequency()
and HighResolutionTimer::Period()
function.
uint64 countStart = HighResolutionTimer::Counter();
...
while (HighResolutionTimer::Counter() < countEnd);
Sleep¶
The Sleep API allows to voluntarily return the control back to the scheduler. The only exception is the Sleep::Busy
which waits for a given time to elapse without yielding the CPU.
...
MARTe::Sleep::Sec(1e-3);
...
Semaphores¶
The framework offers three distinct sets of portables semaphores:
MutexSem: mutex semaphore that offers exclusive access to a critical area;
EventSem: barrier semaphore that, after being released, allows shared access to a critical area;
FastPollingMutexSem and FastPollingEventSem: mutex and event semaphores that do not require an operating system scheduler. Both work by polling, with atomic operations, a given memory location.
...
MARTe::MutexSem mutexSem;
mutexSem.Create(false);
if(!mutexSem.Lock()){
...
if(!mutexSem.UnLock()){
...
The event semaphores need the Event::Reset
method to be called in order to lower the barrier.
Warning
The Event::Reset
operation is not atomic. As consequence, depending on the specific use-case, it may require a mutex semaphore to protect access to a given shared resource while this operating is being performed.
...
MARTe::EventSem eventSem;
eventSem.Create();
...
mutexSem.Lock();
if (needsReset) {
needsReset = false;
eventSem.Reset();
}
mutexSem.UnLock();
eventSem.Wait();
Examples¶
Atomic¶
The following example demonstrates how to use the Atomic API.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | /**
* @file AtomicExample1.cpp
* @brief Source file for class AtomicExample1
* @date 23/04/2018
* @author Andre Neto
*
* @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
* the Development of Fusion Energy ('Fusion for Energy').
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved
* by the European Commission - subsequent versions of the EUPL (the "Licence")
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
*
* @warning Unless required by applicable law or agreed to in writing,
* software distributed under the Licence is distributed on an "AS IS"
* basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the Licence permissions and limitations under the Licence.
* @details This source file contains the definition of all the methods for
* the class AtomicExample1 (public, protected, and private). Be aware that some
* methods, such as those inline could be defined on the header file, instead.
*/
/*---------------------------------------------------------------------------*/
/* Standard header includes */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Project header includes */
/*---------------------------------------------------------------------------*/
#include "AdvancedErrorManagement.h"
#include "Atomic.h"
#include "ErrorLoggerExample.h"
#include "Sleep.h"
#include "Threads.h"
/*---------------------------------------------------------------------------*/
/* Static definitions */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Method definitions */
/*---------------------------------------------------------------------------*/
//The lock variable
static MARTe::int32 locked = 0;
//Unlock after sleeping
static void UnlockWithTestAndSet (const void * const args) {
MARTe::Sleep::Sec(2.0);
locked = 0;
}
int main(int argc, char *argv[]) {
using namespace MARTe;
SetErrorProcessFunction(&ErrorProcessExampleFunction);
int32 a = 3;
int32 b = 4;
REPORT_ERROR_STATIC(ErrorManagement::Information, "Starting with a=%d b=%d", a, b);
//Exchange
b = Atomic::Exchange(&a, b);
REPORT_ERROR_STATIC(ErrorManagement::Information, "After exchanging a=%d b=%d", a, b);
//Atomic increment
Atomic::Increment(&a);
REPORT_ERROR_STATIC(ErrorManagement::Information, "After incrementing a=%d", a);
locked = 1;
//Try to enter a locked region
if (!Atomic::TestAndSet(&locked)) {
REPORT_ERROR_STATIC(ErrorManagement::Information, "As expected TestAndSet failed");
}
locked = 0;
if (!Atomic::TestAndSet(&locked)) {
REPORT_ERROR_STATIC(ErrorManagement::FatalError, "TestAndSet and failed");
}
//Lock again
REPORT_ERROR_STATIC(ErrorManagement::Information, "locked should now be 1 locked = %d", locked);
//Create thread to perform the unlock
REPORT_ERROR_STATIC(ErrorManagement::Information, "Going to wait for thread to unlock");
Threads::BeginThread(UnlockWithTestAndSet);
//Spin lock
while (!Atomic::TestAndSet(&locked))
;
REPORT_ERROR_STATIC(ErrorManagement::Information, "Unlocked by thread");
return 0;
}
|
HighResolutionTimer¶
The following is an example of a possible use of the HighResolutionTimer.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | /**
* @file HighResolutionTimerExample1.cpp
* @brief Source file for class HighResolutionTimerExample1
* @date 23/04/2018
* @author Andre Neto
*
* @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
* the Development of Fusion Energy ('Fusion for Energy').
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved
* by the European Commission - subsequent versions of the EUPL (the "Licence")
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
*
* @warning Unless required by applicable law or agreed to in writing,
* software distributed under the Licence is distributed on an "AS IS"
* basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the Licence permissions and limitations under the Licence.
* @details This source file contains the definition of all the methods for
* the class HighResolutionTimerExample1 (public, protected, and private). Be aware that some
* methods, such as those inline could be defined on the header file, instead.
*/
/*---------------------------------------------------------------------------*/
/* Standard header includes */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Project header includes */
/*---------------------------------------------------------------------------*/
#include "AdvancedErrorManagement.h"
#include "ErrorLoggerExample.h"
#include "HighResolutionTimer.h"
/*---------------------------------------------------------------------------*/
/* Static definitions */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Method definitions */
/*---------------------------------------------------------------------------*/
int main(int argc, char *argv[]) {
using namespace MARTe;
SetErrorProcessFunction(&ErrorProcessExampleFunction);
float64 sleepSeconds = 1.1;
float64 countUntilF = sleepSeconds * HighResolutionTimer::Frequency();
uint64 countUntil = static_cast<uint64>(countUntilF);
uint64 countStart = HighResolutionTimer::Counter();
uint64 countEnd = countStart + countUntil;
while (HighResolutionTimer::Counter() < countEnd);
float64 countDiff = static_cast<float64>(HighResolutionTimer::Counter() - countStart);
float64 sleptSeconds = countDiff * HighResolutionTimer::Period();
REPORT_ERROR_STATIC(ErrorManagement::Information, "Was asked to wait for %e and waited for %e", sleepSeconds, sleptSeconds);
return 0;
}
|
Instructions on how to compile and execute the examples can be found here.
Threads¶
The following example illustrates how to manage threads.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | /**
* @file ThreadsExample1.cpp
* @brief Source file for class ThreadsExample1
* @date 23/08/2018
* @author Andre Neto
*
* @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
* the Development of Fusion Energy ('Fusion for Energy').
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved
* by the European Commission - subsequent versions of the EUPL (the "Licence")
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
*
* @warning Unless required by applicable law or agreed to in writing,
* software distributed under the Licence is distributed on an "AS IS"
* basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the Licence permissions and limitations under the Licence.
* @details This source file contains the definition of all the methods for
* the class ThreadsExample1 (public, protected, and private). Be aware that some
* methods, such as those inline could be defined on the header file, instead.
*/
/*---------------------------------------------------------------------------*/
/* Standard header includes */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Project header includes */
/*---------------------------------------------------------------------------*/
#include "AdvancedErrorManagement.h"
#include "ErrorLoggerExample.h"
#include "Sleep.h"
#include "StreamString.h"
#include "Threads.h"
#include "ThreadInformation.h"
/*---------------------------------------------------------------------------*/
/* Static definitions */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Method definitions */
/*---------------------------------------------------------------------------*/
//An exit condition for all the threads
static MARTe::int32 exitAfterCalls = 500;
//Shared variable to be incremented by the threads
static MARTe::int32 sharedVariable = 0;
//Simulate complicated analysis
static void ComplexAnalysis(MARTe::float32 sec) {
MARTe::Sleep::Sec(sec);
}
//Thread function call back
static void IncrementDecrementFunction(const void * const params) {
using namespace MARTe;
float32 *sleepSec = (float32 *) params;
ThreadInformation info;
Threads::GetThreadInfoCopy(info, Threads::Id());
REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "Thread %s started", info.ThreadName());
while (exitAfterCalls > 0) {
sharedVariable++;
ComplexAnalysis(*sleepSec);
sharedVariable--;
exitAfterCalls--;
}
}
int main(int argc, char *argv[]) {
using namespace MARTe;
SetErrorProcessFunction(&ErrorProcessExampleFunction);
ProcessorType::SetDefaultCPUs(0x1u);
int32 numberOfThreads = 10;
int32 i = 0;
float32 *sleepTimes = new float32[numberOfThreads];
REPORT_ERROR_STATIC(ErrorManagement::Information, "Number of threads = %d", numberOfThreads)
;
for (i = 0; i < numberOfThreads; i++) {
StreamString threadName;
threadName.Printf("Thread-%d", i);
sleepTimes[i] = ((i + 1) * 1e-3);
Threads::BeginThread(&IncrementDecrementFunction, &sleepTimes[i], THREADS_DEFAULT_STACKSIZE, threadName.Buffer(), ExceptionHandler::NotHandled, 0x1);
}
//Wait for the thread to run for exitAfterCalls times
while (exitAfterCalls > 0) {
MARTe::Sleep::Sec(1e-3);
}
REPORT_ERROR_STATIC(ErrorManagement::Information, "Value of sharedVariable = %d", sharedVariable);
delete sleepTimes;
return 0;
}
|
Semaphores¶
The following is an example of the use of mutex and event semaphores and on how to query the thread properties.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | /**
* @file ThreadsExample2.cpp
* @brief Source file for class ThreadsExample2
* @date 23/04/2018
* @author Andre Neto
*
* @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
* the Development of Fusion Energy ('Fusion for Energy').
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved
* by the European Commission - subsequent versions of the EUPL (the "Licence")
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
*
* @warning Unless required by applicable law or agreed to in writing,
* software distributed under the Licence is distributed on an "AS IS"
* basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the Licence permissions and limitations under the Licence.
* @details This source file contains the definition of all the methods for
* the class ThreadsExample2 (public, protected, and private). Be aware that some
* methods, such as those inline could be defined on the header file, instead.
*/
/*---------------------------------------------------------------------------*/
/* Standard header includes */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Project header includes */
/*---------------------------------------------------------------------------*/
#include "AdvancedErrorManagement.h"
#include "ErrorLoggerExample.h"
#include "EventSem.h"
#include "MutexSem.h"
#include "Sleep.h"
#include "StreamString.h"
#include "Threads.h"
#include "ThreadInformation.h"
/*---------------------------------------------------------------------------*/
/* Static definitions */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Method definitions */
/*---------------------------------------------------------------------------*/
//An exit condition for all the threads
static MARTe::int32 exitAfterCalls = 50;
//Shared variable to be incremented by the threads
static MARTe::int32 sharedVariable = 0;
//Event semaphore so that all the threads start at the same time
static MARTe::EventSem eventSem;
//Mutex semaphore protecting the sharedVariable
static MARTe::MutexSem mutexSem;
//The number of threads
static MARTe::int32 numberOfThreads = 10;
//The number of threads to be started
static MARTe::int32 numberOfThreadsLeftToStart = numberOfThreads;
//The number of threads terminated
static MARTe::int32 numberOfThreadsTerminated = 0;
//Simulate complicated analysis
static void ComplexAnalysis(float sec){
MARTe::Sleep::Sec(sec);
}
//Thread function call back
static void IncrementDecrementFunction(const void * const params){
using namespace MARTe;
float32 *sleepSec = (float32 *) params;
ThreadInformation info;
Threads::GetThreadInfoCopy(info, Threads::Id());
REPORT_ERROR_STATIC(ErrorManagement::Information, "Thread %s waiting for event sem", info.ThreadName());
numberOfThreadsLeftToStart--;
if(!eventSem.Wait()){
REPORT_ERROR_STATIC(ErrorManagement::FatalError, "Thread %s failed to wait in event sem (timeout?)", info.ThreadName());
}
REPORT_ERROR_STATIC(ErrorManagement::Information, "Thread %s started", info.ThreadName());
while(exitAfterCalls > 0){
//The mutex protects this region of code
if(!mutexSem.Lock()){
REPORT_ERROR_STATIC(ErrorManagement::FatalError, "Thread %s failed to wait in mutex sem (timeout?)", info.ThreadName());
}
sharedVariable++;
ComplexAnalysis(*sleepSec);
sharedVariable--;
exitAfterCalls--;
if(!mutexSem.UnLock()){
REPORT_ERROR_STATIC(ErrorManagement::FatalError, "Thread %s failed to unlock mutex sem", info.ThreadName());
}
}
numberOfThreadsTerminated++;
}
int main(int argc, char *argv[]){
using namespace MARTe;
SetErrorProcessFunction(&ErrorProcessExampleFunction);
int32 i = 0;
float32 *sleepTimes = new float32[numberOfThreads];
//Configure the semaphores
eventSem.Create();
eventSem.Reset();
mutexSem.Create(false);
REPORT_ERROR_STATIC(ErrorManagement::Information, "Number of threads = %d", numberOfThreads);
for(i=0; i<numberOfThreads; i++){
StreamString threadName;
threadName.Printf("Thread-%d", i);
sleepTimes[i] = ((i + 1) * 1e-3);
Threads::BeginThread(&IncrementDecrementFunction, &sleepTimes[i], THREADS_DEFAULT_STACKSIZE, threadName.Buffer(), ExceptionHandler::NotHandled, 0x1);
}
//Wait for all threads to be ready and waiting on the event semaphore (this isn't actually needed, but guarantees that the
//REPORT_ERROR_STATIC come in the right order)
while(!Atomic::TestAndSet(&numberOfThreadsLeftToStart));
//List all the threads
int32 numberOfThreads = Threads::NumberOfThreads();
for (i=0; i<numberOfThreads; i++) {
ThreadIdentifier tid = Threads::FindByIndex(i);
ThreadInformation tinfo;
Threads::GetThreadInfoCopy(tinfo, tid);
const char8 * const threadName = tinfo.ThreadName();
Threads::PriorityClassType pclass = tinfo.GetPriorityClass();
uint8 plevel = tinfo.GetPriorityLevel();
REPORT_ERROR_STATIC(ErrorManagement::Information, "Name: %s Class: %d Level: %d", threadName, pclass, plevel);
}
REPORT_ERROR_STATIC(ErrorManagement::Information, "Starting all threads!");
//Allow all threads to start
eventSem.Post();
//Wait for the thread to run for exitAfterCalls times
while(exitAfterCalls > 0){
MARTe::Sleep::Sec(1e-3);
}
//Wait to check if some calculation are still to be terminated
while (numberOfThreadsTerminated < numberOfThreads) {
MARTe::Sleep::Sec(1e-3);
}
REPORT_ERROR_STATIC(ErrorManagement::Information, "Value of sharedVariable = %d (should be zero)", sharedVariable);
mutexSem.Close();
delete sleepTimes;
return 0;
}
|
FastPolling Semaphores¶
The same example as above, but implemented using the FastPolling semaphores.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | /**
* @file ThreadsExample2.cpp
* @brief Source file for class ThreadsExample2
* @date 23/04/2018
* @author Andre Neto
*
* @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
* the Development of Fusion Energy ('Fusion for Energy').
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved
* by the European Commission - subsequent versions of the EUPL (the "Licence")
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
*
* @warning Unless required by applicable law or agreed to in writing,
* software distributed under the Licence is distributed on an "AS IS"
* basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the Licence permissions and limitations under the Licence.
* @details This source file contains the definition of all the methods for
* the class ThreadsExample2 (public, protected, and private). Be aware that some
* methods, such as those inline could be defined on the header file, instead.
*/
/*---------------------------------------------------------------------------*/
/* Standard header includes */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Project header includes */
/*---------------------------------------------------------------------------*/
#include "AdvancedErrorManagement.h"
#include "ErrorLoggerExample.h"
#include "FastPollingEventSem.h"
#include "FastPollingMutexSem.h"
#include "Sleep.h"
#include "StreamString.h"
#include "Threads.h"
#include "ThreadInformation.h"
/*---------------------------------------------------------------------------*/
/* Static definitions */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Method definitions */
/*---------------------------------------------------------------------------*/
//An exit condition for all the threads
static MARTe::int32 exitAfterCalls = 50;
//Shared variable to be incremented by the threads
static MARTe::int32 sharedVariable = 0;
//Event semaphore so that all the threads start at the same time
static MARTe::FastPollingEventSem eventSem;
//Mutex semaphore protecting the sharedVariable
static MARTe::FastPollingMutexSem mutexSem;
//The number of threads
static MARTe::int32 numberOfThreads = 10;
//The number of threads to be started
static MARTe::int32 numberOfThreadsLeftToStart = numberOfThreads;
//The number of threads terminated
static MARTe::int32 numberOfThreadsTerminated = 0;
//Simulate complicated analysis
static void ComplexAnalysis(float sec){
MARTe::Sleep::Sec(sec);
}
//Thread function call back
static void IncrementDecrementFunction(const void * const params){
using namespace MARTe;
float32 *sleepSec = (float32 *) params;
ThreadInformation info;
Threads::GetThreadInfoCopy(info, Threads::Id());
REPORT_ERROR_STATIC(ErrorManagement::Information, "Thread %s waiting for event sem", info.ThreadName());
numberOfThreadsLeftToStart--;
if(!eventSem.FastWait()){
REPORT_ERROR_STATIC(ErrorManagement::FatalError, "Thread %s failed to wait in event sem (timeout?)", info.ThreadName());
}
REPORT_ERROR_STATIC(ErrorManagement::Information, "Thread %s started", info.ThreadName());
while(exitAfterCalls > 0){
//The mutex protects this region of code
if(!mutexSem.FastLock()){
REPORT_ERROR_STATIC(ErrorManagement::FatalError, "Thread %s failed to wait in mutex sem (timeout?)", info.ThreadName());
}
sharedVariable++;
ComplexAnalysis(*sleepSec);
sharedVariable--;
exitAfterCalls--;
mutexSem.FastUnLock();
}
numberOfThreadsTerminated++;
}
int main(int argc, char *argv[]){
using namespace MARTe;
SetErrorProcessFunction(&ErrorProcessExampleFunction);
int32 i = 0;
float32 *sleepTimes = new float32[numberOfThreads];
//Configure the semaphores
eventSem.Create();
eventSem.Reset();
mutexSem.Create(false);
REPORT_ERROR_STATIC(ErrorManagement::Information, "Number of threads = %d", numberOfThreads);
for(i=0; i<numberOfThreads; i++){
StreamString threadName;
threadName.Printf("Thread-%d", i);
sleepTimes[i] = ((i + 1) * 1e-3);
Threads::BeginThread(&IncrementDecrementFunction, &sleepTimes[i], THREADS_DEFAULT_STACKSIZE, threadName.Buffer(), ExceptionHandler::NotHandled, 0x1);
}
//FastWait for all threads to be ready and waiting on the event semaphore (this isn't actually needed, but guarantees that the
//REPORT_ERROR_STATIC come in the right order)
while(!Atomic::TestAndSet(&numberOfThreadsLeftToStart));
REPORT_ERROR_STATIC(ErrorManagement::Information, "Starting all threads!");
//Allow all threads to start
eventSem.FastPost();
//FastWait for the thread to run for exitAfterCalls times
while(exitAfterCalls > 0){
MARTe::Sleep::Sec(1e-3);
}
//Wait to check if some calculation are still to be terminated
while (numberOfThreadsTerminated < numberOfThreads) {
MARTe::Sleep::Sec(1e-3);
}
REPORT_ERROR_STATIC(ErrorManagement::Information, "Value of sharedVariable = %d (should be zero)", sharedVariable);
delete sleepTimes;
return 0;
}
|
Instructions on how to compile and execute the examples can be found here.