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 * @file AtomicExample1.cpp
3 * @brief Source file for class AtomicExample1
4 * @date 23/04/2018
5 * @author Andre Neto
6 *
7 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
8 * the Development of Fusion Energy ('Fusion for Energy').
9 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
10 * by the European Commission - subsequent versions of the EUPL (the "Licence")
11 * You may not use this work except in compliance with the Licence.
12 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
13 *
14 * @warning Unless required by applicable law or agreed to in writing,
15 * software distributed under the Licence is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17 * or implied. See the Licence permissions and limitations under the Licence.
18
19 * @details This source file contains the definition of all the methods for
20 * the class AtomicExample1 (public, protected, and private). Be aware that some
21 * methods, such as those inline could be defined on the header file, instead.
22 */
23
24/*---------------------------------------------------------------------------*/
25/* Standard header includes */
26/*---------------------------------------------------------------------------*/
27
28/*---------------------------------------------------------------------------*/
29/* Project header includes */
30/*---------------------------------------------------------------------------*/
31#include "AdvancedErrorManagement.h"
32#include "Atomic.h"
33#include "ErrorLoggerExample.h"
34#include "Sleep.h"
35#include "Threads.h"
36
37/*---------------------------------------------------------------------------*/
38/* Static definitions */
39/*---------------------------------------------------------------------------*/
40
41/*---------------------------------------------------------------------------*/
42/* Method definitions */
43/*---------------------------------------------------------------------------*/
44
45//The lock variable
46static MARTe::int32 locked = 0;
47
48//Unlock after sleeping
49static void UnlockWithTestAndSet (const void * const args) {
50 MARTe::Sleep::Sec(2.0);
51 locked = 0;
52}
53
54int main(int argc, char *argv[]) {
55 using namespace MARTe;
56 SetErrorProcessFunction(&ErrorProcessExampleFunction);
57
58 int32 a = 3;
59 int32 b = 4;
60
61 REPORT_ERROR_STATIC(ErrorManagement::Information, "Starting with a=%d b=%d", a, b);
62 //Exchange
63 b = Atomic::Exchange(&a, b);
64 REPORT_ERROR_STATIC(ErrorManagement::Information, "After exchanging a=%d b=%d", a, b);
65 //Atomic increment
66 Atomic::Increment(&a);
67 REPORT_ERROR_STATIC(ErrorManagement::Information, "After incrementing a=%d", a);
68
69 locked = 1;
70 //Try to enter a locked region
71 if (!Atomic::TestAndSet(&locked)) {
72 REPORT_ERROR_STATIC(ErrorManagement::Information, "As expected TestAndSet failed");
73 }
74 locked = 0;
75 if (!Atomic::TestAndSet(&locked)) {
76 REPORT_ERROR_STATIC(ErrorManagement::FatalError, "TestAndSet and failed");
77 }
78
79 //Lock again
80 REPORT_ERROR_STATIC(ErrorManagement::Information, "locked should now be 1 locked = %d", locked);
81 //Create thread to perform the unlock
82 REPORT_ERROR_STATIC(ErrorManagement::Information, "Going to wait for thread to unlock");
83 Threads::BeginThread(UnlockWithTestAndSet);
84 //Spin lock
85 while (!Atomic::TestAndSet(&locked))
86 ;
87
88 REPORT_ERROR_STATIC(ErrorManagement::Information, "Unlocked by thread");
89
90 return 0;
91}
HighResolutionTimer
The following is an example of a possible use of the HighResolutionTimer.
1/**
2 * @file HighResolutionTimerExample1.cpp
3 * @brief Source file for class HighResolutionTimerExample1
4 * @date 23/04/2018
5 * @author Andre Neto
6 *
7 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
8 * the Development of Fusion Energy ('Fusion for Energy').
9 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
10 * by the European Commission - subsequent versions of the EUPL (the "Licence")
11 * You may not use this work except in compliance with the Licence.
12 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
13 *
14 * @warning Unless required by applicable law or agreed to in writing,
15 * software distributed under the Licence is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17 * or implied. See the Licence permissions and limitations under the Licence.
18
19 * @details This source file contains the definition of all the methods for
20 * the class HighResolutionTimerExample1 (public, protected, and private). Be aware that some
21 * methods, such as those inline could be defined on the header file, instead.
22 */
23
24/*---------------------------------------------------------------------------*/
25/* Standard header includes */
26/*---------------------------------------------------------------------------*/
27
28/*---------------------------------------------------------------------------*/
29/* Project header includes */
30/*---------------------------------------------------------------------------*/
31#include "AdvancedErrorManagement.h"
32#include "ErrorLoggerExample.h"
33#include "HighResolutionTimer.h"
34
35/*---------------------------------------------------------------------------*/
36/* Static definitions */
37/*---------------------------------------------------------------------------*/
38
39/*---------------------------------------------------------------------------*/
40/* Method definitions */
41/*---------------------------------------------------------------------------*/
42
43
44int main(int argc, char *argv[]) {
45 using namespace MARTe;
46 SetErrorProcessFunction(&ErrorProcessExampleFunction);
47
48 float64 sleepSeconds = 1.1;
49 float64 countUntilF = sleepSeconds * HighResolutionTimer::Frequency();
50 uint64 countUntil = static_cast<uint64>(countUntilF);
51
52 uint64 countStart = HighResolutionTimer::Counter();
53 uint64 countEnd = countStart + countUntil;
54 while (HighResolutionTimer::Counter() < countEnd);
55 float64 countDiff = static_cast<float64>(HighResolutionTimer::Counter() - countStart);
56 float64 sleptSeconds = countDiff * HighResolutionTimer::Period();
57 REPORT_ERROR_STATIC(ErrorManagement::Information, "Was asked to wait for %e and waited for %e", sleepSeconds, sleptSeconds);
58
59 return 0;
60}
Instructions on how to compile and execute the examples can be found here.
Threads
The following example illustrates how to manage threads.
1/**
2 * @file ThreadsExample1.cpp
3 * @brief Source file for class ThreadsExample1
4 * @date 23/08/2018
5 * @author Andre Neto
6 *
7 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
8 * the Development of Fusion Energy ('Fusion for Energy').
9 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
10 * by the European Commission - subsequent versions of the EUPL (the "Licence")
11 * You may not use this work except in compliance with the Licence.
12 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
13 *
14 * @warning Unless required by applicable law or agreed to in writing,
15 * software distributed under the Licence is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17 * or implied. See the Licence permissions and limitations under the Licence.
18
19 * @details This source file contains the definition of all the methods for
20 * the class ThreadsExample1 (public, protected, and private). Be aware that some
21 * methods, such as those inline could be defined on the header file, instead.
22 */
23
24/*---------------------------------------------------------------------------*/
25/* Standard header includes */
26/*---------------------------------------------------------------------------*/
27
28/*---------------------------------------------------------------------------*/
29/* Project header includes */
30/*---------------------------------------------------------------------------*/
31#include "AdvancedErrorManagement.h"
32#include "ErrorLoggerExample.h"
33#include "Sleep.h"
34#include "StreamString.h"
35#include "Threads.h"
36#include "ThreadInformation.h"
37
38/*---------------------------------------------------------------------------*/
39/* Static definitions */
40/*---------------------------------------------------------------------------*/
41
42/*---------------------------------------------------------------------------*/
43/* Method definitions */
44/*---------------------------------------------------------------------------*/
45
46//An exit condition for all the threads
47static MARTe::int32 exitAfterCalls = 500;
48
49//Shared variable to be incremented by the threads
50static MARTe::int32 sharedVariable = 0;
51
52//Simulate complicated analysis
53static void ComplexAnalysis(MARTe::float32 sec) {
54 MARTe::Sleep::Sec(sec);
55}
56
57//Thread function call back
58static void IncrementDecrementFunction(const void * const params) {
59 using namespace MARTe;
60 float32 *sleepSec = (float32 *) params;
61 ThreadInformation info;
62 Threads::GetThreadInfoCopy(info, Threads::Id());
63 REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information, "Thread %s started", info.ThreadName());
64 while (exitAfterCalls > 0) {
65 sharedVariable++;
66 ComplexAnalysis(*sleepSec);
67 sharedVariable--;
68 exitAfterCalls--;
69 }
70}
71
72int main(int argc, char *argv[]) {
73 using namespace MARTe;
74 SetErrorProcessFunction(&ErrorProcessExampleFunction);
75 ProcessorType::SetDefaultCPUs(0x1u);
76
77 int32 numberOfThreads = 10;
78 int32 i = 0;
79 float32 *sleepTimes = new float32[numberOfThreads];
80
81 REPORT_ERROR_STATIC(ErrorManagement::Information, "Number of threads = %d", numberOfThreads)
82 ;
83 for (i = 0; i < numberOfThreads; i++) {
84 StreamString threadName;
85 threadName.Printf("Thread-%d", i);
86 sleepTimes[i] = ((i + 1) * 1e-3);
87 Threads::BeginThread(&IncrementDecrementFunction, &sleepTimes[i], THREADS_DEFAULT_STACKSIZE, threadName.Buffer(), ExceptionHandler::NotHandled, 0x1);
88 }
89 //Wait for the thread to run for exitAfterCalls times
90 while (exitAfterCalls > 0) {
91 MARTe::Sleep::Sec(1e-3);
92 }
93 REPORT_ERROR_STATIC(ErrorManagement::Information, "Value of sharedVariable = %d", sharedVariable);
94 delete sleepTimes;
95 return 0;
96}
Semaphores
The following is an example of the use of mutex and event semaphores and on how to query the thread properties.
1/**
2 * @file ThreadsExample2.cpp
3 * @brief Source file for class ThreadsExample2
4 * @date 23/04/2018
5 * @author Andre Neto
6 *
7 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
8 * the Development of Fusion Energy ('Fusion for Energy').
9 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
10 * by the European Commission - subsequent versions of the EUPL (the "Licence")
11 * You may not use this work except in compliance with the Licence.
12 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
13 *
14 * @warning Unless required by applicable law or agreed to in writing,
15 * software distributed under the Licence is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17 * or implied. See the Licence permissions and limitations under the Licence.
18
19 * @details This source file contains the definition of all the methods for
20 * the class ThreadsExample2 (public, protected, and private). Be aware that some
21 * methods, such as those inline could be defined on the header file, instead.
22 */
23
24/*---------------------------------------------------------------------------*/
25/* Standard header includes */
26/*---------------------------------------------------------------------------*/
27
28/*---------------------------------------------------------------------------*/
29/* Project header includes */
30/*---------------------------------------------------------------------------*/
31#include "AdvancedErrorManagement.h"
32#include "ErrorLoggerExample.h"
33#include "EventSem.h"
34#include "MutexSem.h"
35#include "Sleep.h"
36#include "StreamString.h"
37#include "Threads.h"
38#include "ThreadInformation.h"
39/*---------------------------------------------------------------------------*/
40/* Static definitions */
41/*---------------------------------------------------------------------------*/
42
43/*---------------------------------------------------------------------------*/
44/* Method definitions */
45/*---------------------------------------------------------------------------*/
46
47//An exit condition for all the threads
48static MARTe::int32 exitAfterCalls = 50;
49
50//Shared variable to be incremented by the threads
51static MARTe::int32 sharedVariable = 0;
52
53//Event semaphore so that all the threads start at the same time
54static MARTe::EventSem eventSem;
55
56//Mutex semaphore protecting the sharedVariable
57static MARTe::MutexSem mutexSem;
58
59//The number of threads
60static MARTe::int32 numberOfThreads = 10;
61
62//The number of threads to be started
63static MARTe::int32 numberOfThreadsLeftToStart = numberOfThreads;
64
65//The number of threads terminated
66static MARTe::int32 numberOfThreadsTerminated = 0;
67
68//Simulate complicated analysis
69static void ComplexAnalysis(float sec){
70 MARTe::Sleep::Sec(sec);
71}
72
73//Thread function call back
74static void IncrementDecrementFunction(const void * const params){
75 using namespace MARTe;
76 float32 *sleepSec = (float32 *) params;
77 ThreadInformation info;
78 Threads::GetThreadInfoCopy(info, Threads::Id());
79 REPORT_ERROR_STATIC(ErrorManagement::Information, "Thread %s waiting for event sem", info.ThreadName());
80 numberOfThreadsLeftToStart--;
81 if(!eventSem.Wait()){
82 REPORT_ERROR_STATIC(ErrorManagement::FatalError, "Thread %s failed to wait in event sem (timeout?)", info.ThreadName());
83 }
84 REPORT_ERROR_STATIC(ErrorManagement::Information, "Thread %s started", info.ThreadName());
85 while(exitAfterCalls > 0){
86 //The mutex protects this region of code
87 if(!mutexSem.Lock()){
88 REPORT_ERROR_STATIC(ErrorManagement::FatalError, "Thread %s failed to wait in mutex sem (timeout?)", info.ThreadName());
89 }
90 sharedVariable++;
91 ComplexAnalysis(*sleepSec);
92 sharedVariable--;
93 exitAfterCalls--;
94 if(!mutexSem.UnLock()){
95 REPORT_ERROR_STATIC(ErrorManagement::FatalError, "Thread %s failed to unlock mutex sem", info.ThreadName());
96 }
97 }
98 numberOfThreadsTerminated++;
99}
100
101int main(int argc, char *argv[]){
102 using namespace MARTe;
103 SetErrorProcessFunction(&ErrorProcessExampleFunction);
104
105 int32 i = 0;
106
107 float32 *sleepTimes = new float32[numberOfThreads];
108 //Configure the semaphores
109 eventSem.Create();
110 eventSem.Reset();
111 mutexSem.Create(false);
112
113 REPORT_ERROR_STATIC(ErrorManagement::Information, "Number of threads = %d", numberOfThreads);
114 for(i=0; i<numberOfThreads; i++){
115 StreamString threadName;
116 threadName.Printf("Thread-%d", i);
117 sleepTimes[i] = ((i + 1) * 1e-3);
118 Threads::BeginThread(&IncrementDecrementFunction, &sleepTimes[i], THREADS_DEFAULT_STACKSIZE, threadName.Buffer(), ExceptionHandler::NotHandled, 0x1);
119 }
120 //Wait for all threads to be ready and waiting on the event semaphore (this isn't actually needed, but guarantees that the
121 //REPORT_ERROR_STATIC come in the right order)
122 while(!Atomic::TestAndSet(&numberOfThreadsLeftToStart));
123
124 //List all the threads
125 int32 numberOfThreads = Threads::NumberOfThreads();
126 for (i=0; i<numberOfThreads; i++) {
127 ThreadIdentifier tid = Threads::FindByIndex(i);
128 ThreadInformation tinfo;
129 Threads::GetThreadInfoCopy(tinfo, tid);
130 const char8 * const threadName = tinfo.ThreadName();
131 Threads::PriorityClassType pclass = tinfo.GetPriorityClass();
132 uint8 plevel = tinfo.GetPriorityLevel();
133 REPORT_ERROR_STATIC(ErrorManagement::Information, "Name: %s Class: %d Level: %d", threadName, pclass, plevel);
134 }
135
136 REPORT_ERROR_STATIC(ErrorManagement::Information, "Starting all threads!");
137 //Allow all threads to start
138 eventSem.Post();
139 //Wait for the thread to run for exitAfterCalls times
140 while(exitAfterCalls > 0){
141 MARTe::Sleep::Sec(1e-3);
142 }
143 //Wait to check if some calculation are still to be terminated
144 while (numberOfThreadsTerminated < numberOfThreads) {
145 MARTe::Sleep::Sec(1e-3);
146 }
147 REPORT_ERROR_STATIC(ErrorManagement::Information, "Value of sharedVariable = %d (should be zero)", sharedVariable);
148 mutexSem.Close();
149 delete sleepTimes;
150 return 0;
151}
FastPolling Semaphores
The same example as above, but implemented using the FastPolling semaphores.
1/**
2 * @file ThreadsExample2.cpp
3 * @brief Source file for class ThreadsExample2
4 * @date 23/04/2018
5 * @author Andre Neto
6 *
7 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
8 * the Development of Fusion Energy ('Fusion for Energy').
9 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
10 * by the European Commission - subsequent versions of the EUPL (the "Licence")
11 * You may not use this work except in compliance with the Licence.
12 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
13 *
14 * @warning Unless required by applicable law or agreed to in writing,
15 * software distributed under the Licence is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17 * or implied. See the Licence permissions and limitations under the Licence.
18
19 * @details This source file contains the definition of all the methods for
20 * the class ThreadsExample2 (public, protected, and private). Be aware that some
21 * methods, such as those inline could be defined on the header file, instead.
22 */
23
24/*---------------------------------------------------------------------------*/
25/* Standard header includes */
26/*---------------------------------------------------------------------------*/
27
28/*---------------------------------------------------------------------------*/
29/* Project header includes */
30/*---------------------------------------------------------------------------*/
31#include "AdvancedErrorManagement.h"
32#include "ErrorLoggerExample.h"
33#include "FastPollingEventSem.h"
34#include "FastPollingMutexSem.h"
35#include "Sleep.h"
36#include "StreamString.h"
37#include "Threads.h"
38#include "ThreadInformation.h"
39
40/*---------------------------------------------------------------------------*/
41/* Static definitions */
42/*---------------------------------------------------------------------------*/
43
44/*---------------------------------------------------------------------------*/
45/* Method definitions */
46/*---------------------------------------------------------------------------*/
47
48//An exit condition for all the threads
49static MARTe::int32 exitAfterCalls = 50;
50
51//Shared variable to be incremented by the threads
52static MARTe::int32 sharedVariable = 0;
53
54//Event semaphore so that all the threads start at the same time
55static MARTe::FastPollingEventSem eventSem;
56
57//Mutex semaphore protecting the sharedVariable
58static MARTe::FastPollingMutexSem mutexSem;
59
60//The number of threads
61static MARTe::int32 numberOfThreads = 10;
62
63//The number of threads to be started
64static MARTe::int32 numberOfThreadsLeftToStart = numberOfThreads;
65
66//The number of threads terminated
67static MARTe::int32 numberOfThreadsTerminated = 0;
68
69//Simulate complicated analysis
70static void ComplexAnalysis(float sec){
71 MARTe::Sleep::Sec(sec);
72}
73
74//Thread function call back
75static void IncrementDecrementFunction(const void * const params){
76 using namespace MARTe;
77 float32 *sleepSec = (float32 *) params;
78 ThreadInformation info;
79 Threads::GetThreadInfoCopy(info, Threads::Id());
80 REPORT_ERROR_STATIC(ErrorManagement::Information, "Thread %s waiting for event sem", info.ThreadName());
81 numberOfThreadsLeftToStart--;
82 if(!eventSem.FastWait()){
83 REPORT_ERROR_STATIC(ErrorManagement::FatalError, "Thread %s failed to wait in event sem (timeout?)", info.ThreadName());
84 }
85 REPORT_ERROR_STATIC(ErrorManagement::Information, "Thread %s started", info.ThreadName());
86 while(exitAfterCalls > 0){
87 //The mutex protects this region of code
88 if(!mutexSem.FastLock()){
89 REPORT_ERROR_STATIC(ErrorManagement::FatalError, "Thread %s failed to wait in mutex sem (timeout?)", info.ThreadName());
90 }
91 sharedVariable++;
92 ComplexAnalysis(*sleepSec);
93 sharedVariable--;
94 exitAfterCalls--;
95 mutexSem.FastUnLock();
96 }
97 numberOfThreadsTerminated++;
98}
99
100int main(int argc, char *argv[]){
101 using namespace MARTe;
102 SetErrorProcessFunction(&ErrorProcessExampleFunction);
103
104 int32 i = 0;
105
106 float32 *sleepTimes = new float32[numberOfThreads];
107 //Configure the semaphores
108 eventSem.Create();
109 eventSem.Reset();
110 mutexSem.Create(false);
111
112 REPORT_ERROR_STATIC(ErrorManagement::Information, "Number of threads = %d", numberOfThreads);
113 for(i=0; i<numberOfThreads; i++){
114 StreamString threadName;
115 threadName.Printf("Thread-%d", i);
116 sleepTimes[i] = ((i + 1) * 1e-3);
117 Threads::BeginThread(&IncrementDecrementFunction, &sleepTimes[i], THREADS_DEFAULT_STACKSIZE, threadName.Buffer(), ExceptionHandler::NotHandled, 0x1);
118 }
119 //FastWait for all threads to be ready and waiting on the event semaphore (this isn't actually needed, but guarantees that the
120 //REPORT_ERROR_STATIC come in the right order)
121 while(!Atomic::TestAndSet(&numberOfThreadsLeftToStart));
122
123 REPORT_ERROR_STATIC(ErrorManagement::Information, "Starting all threads!");
124 //Allow all threads to start
125 eventSem.FastPost();
126 //FastWait for the thread to run for exitAfterCalls times
127 while(exitAfterCalls > 0){
128 MARTe::Sleep::Sec(1e-3);
129 }
130 //Wait to check if some calculation are still to be terminated
131 while (numberOfThreadsTerminated < numberOfThreads) {
132 MARTe::Sleep::Sec(1e-3);
133 }
134 REPORT_ERROR_STATIC(ErrorManagement::Information, "Value of sharedVariable = %d (should be zero)", sharedVariable);
135 delete sleepTimes;
136 return 0;
137}
Instructions on how to compile and execute the examples can be found here.