Ye Cheng
/
cmsis_rtos_demo_mutex
cmsis rtos demo: mutex
main.cpp@1:1308d7d6d53e, 2013-01-06 (annotated)
- Committer:
- cnhzcy14
- Date:
- Sun Jan 06 15:03:44 2013 +0000
- Revision:
- 1:1308d7d6d53e
- Parent:
- 0:fba50ae123e6
comments
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
cnhzcy14 | 1:1308d7d6d53e | 1 | /***************************************************************************** |
cnhzcy14 | 1:1308d7d6d53e | 2 | * DESCRIPTION: |
cnhzcy14 | 1:1308d7d6d53e | 3 | * This example program illustrates the use of mutex variables |
cnhzcy14 | 1:1308d7d6d53e | 4 | * in a threads program. This version was obtained by modifying the |
cnhzcy14 | 1:1308d7d6d53e | 5 | * serial version of the program (dotprod_serial.c) which performs a |
cnhzcy14 | 1:1308d7d6d53e | 6 | * dot product. The main data is made available to all threads through |
cnhzcy14 | 1:1308d7d6d53e | 7 | * a globally accessible structure. Each thread works on a different |
cnhzcy14 | 1:1308d7d6d53e | 8 | * part of the data. The main thread waits for all the threads to complete |
cnhzcy14 | 1:1308d7d6d53e | 9 | * their computations, and then it prints the resulting sum. |
cnhzcy14 | 1:1308d7d6d53e | 10 | * SOURCE: Vijay Sonnad, IBM |
cnhzcy14 | 1:1308d7d6d53e | 11 | * MODIFICATOR: (Simon) CHENG Ye |
cnhzcy14 | 1:1308d7d6d53e | 12 | * LAST REVISED: 06/JAN/2013 |
cnhzcy14 | 1:1308d7d6d53e | 13 | ******************************************************************************/ |
cnhzcy14 | 1:1308d7d6d53e | 14 | |
cnhzcy14 | 0:fba50ae123e6 | 15 | #include "mbed.h" |
cnhzcy14 | 0:fba50ae123e6 | 16 | #include "cmsis_os.h" |
cnhzcy14 | 0:fba50ae123e6 | 17 | |
cnhzcy14 | 0:fba50ae123e6 | 18 | Serial debug(USBTX, USBRX); |
cnhzcy14 | 0:fba50ae123e6 | 19 | |
cnhzcy14 | 1:1308d7d6d53e | 20 | |
cnhzcy14 | 1:1308d7d6d53e | 21 | /* |
cnhzcy14 | 1:1308d7d6d53e | 22 | * The following structure contains the necessary information |
cnhzcy14 | 1:1308d7d6d53e | 23 | * to allow the function "dotprod" to access its input data and |
cnhzcy14 | 1:1308d7d6d53e | 24 | * place its output into the structure. This structure is |
cnhzcy14 | 1:1308d7d6d53e | 25 | * unchanged from the sequential version. |
cnhzcy14 | 1:1308d7d6d53e | 26 | */ |
cnhzcy14 | 0:fba50ae123e6 | 27 | typedef struct |
cnhzcy14 | 0:fba50ae123e6 | 28 | { |
cnhzcy14 | 0:fba50ae123e6 | 29 | double *a; |
cnhzcy14 | 0:fba50ae123e6 | 30 | double *b; |
cnhzcy14 | 0:fba50ae123e6 | 31 | double sum; |
cnhzcy14 | 0:fba50ae123e6 | 32 | int veclen; |
cnhzcy14 | 0:fba50ae123e6 | 33 | } DOTDATA; |
cnhzcy14 | 0:fba50ae123e6 | 34 | |
cnhzcy14 | 1:1308d7d6d53e | 35 | /* Define globally accessible variables and a mutex */ |
cnhzcy14 | 0:fba50ae123e6 | 36 | #define NUMTHRDS 4 |
cnhzcy14 | 1:1308d7d6d53e | 37 | #define VECLEN 200 //Use a smaller size vector for limited memeory space on mbed |
cnhzcy14 | 0:fba50ae123e6 | 38 | DOTDATA dotstr; |
cnhzcy14 | 0:fba50ae123e6 | 39 | osMutexId stdio_mutex; |
cnhzcy14 | 0:fba50ae123e6 | 40 | osMutexDef(stdio_mutex); |
cnhzcy14 | 0:fba50ae123e6 | 41 | |
cnhzcy14 | 1:1308d7d6d53e | 42 | /* |
cnhzcy14 | 1:1308d7d6d53e | 43 | * The function dotprod is activated when the thread is created. |
cnhzcy14 | 1:1308d7d6d53e | 44 | * As before, all input to this routine is obtained from a structure |
cnhzcy14 | 1:1308d7d6d53e | 45 | * of type DOTDATA and all output from this function is written into |
cnhzcy14 | 1:1308d7d6d53e | 46 | * this structure. The benefit of this approach is apparent for the |
cnhzcy14 | 1:1308d7d6d53e | 47 | * multi-threaded program: when a thread is created we pass a single |
cnhzcy14 | 1:1308d7d6d53e | 48 | * argument to the activated function - typically this argument |
cnhzcy14 | 1:1308d7d6d53e | 49 | * is a thread number. All the other information required by the |
cnhzcy14 | 1:1308d7d6d53e | 50 | * function is accessed from the globally accessible structure. |
cnhzcy14 | 1:1308d7d6d53e | 51 | */ |
cnhzcy14 | 0:fba50ae123e6 | 52 | void dotprod(void const *arg) |
cnhzcy14 | 0:fba50ae123e6 | 53 | { |
cnhzcy14 | 1:1308d7d6d53e | 54 | /* Define and use local variables for convenience */ |
cnhzcy14 | 0:fba50ae123e6 | 55 | osThreadId id; |
cnhzcy14 | 0:fba50ae123e6 | 56 | int i, start, end, len ; |
cnhzcy14 | 0:fba50ae123e6 | 57 | long offset; |
cnhzcy14 | 0:fba50ae123e6 | 58 | double mysum, *x, *y; |
cnhzcy14 | 0:fba50ae123e6 | 59 | offset = (long)arg; |
cnhzcy14 | 0:fba50ae123e6 | 60 | |
cnhzcy14 | 0:fba50ae123e6 | 61 | len = dotstr.veclen; |
cnhzcy14 | 0:fba50ae123e6 | 62 | start = offset*len; |
cnhzcy14 | 0:fba50ae123e6 | 63 | end = start + len; |
cnhzcy14 | 0:fba50ae123e6 | 64 | x = dotstr.a; |
cnhzcy14 | 0:fba50ae123e6 | 65 | y = dotstr.b; |
cnhzcy14 | 0:fba50ae123e6 | 66 | |
cnhzcy14 | 1:1308d7d6d53e | 67 | /* |
cnhzcy14 | 1:1308d7d6d53e | 68 | * Perform the dot product and assign result |
cnhzcy14 | 1:1308d7d6d53e | 69 | * to the appropriate variable in the structure. |
cnhzcy14 | 1:1308d7d6d53e | 70 | */ |
cnhzcy14 | 0:fba50ae123e6 | 71 | mysum = 0; |
cnhzcy14 | 0:fba50ae123e6 | 72 | for (i=start; i<end ; i++) |
cnhzcy14 | 0:fba50ae123e6 | 73 | mysum += (x[i] * y[i]); |
cnhzcy14 | 0:fba50ae123e6 | 74 | |
cnhzcy14 | 1:1308d7d6d53e | 75 | /* |
cnhzcy14 | 1:1308d7d6d53e | 76 | * Lock a mutex prior to updating the value in the shared |
cnhzcy14 | 1:1308d7d6d53e | 77 | * structure, and unlock it upon updating. |
cnhzcy14 | 1:1308d7d6d53e | 78 | */ |
cnhzcy14 | 0:fba50ae123e6 | 79 | osMutexWait(stdio_mutex, osWaitForever); |
cnhzcy14 | 0:fba50ae123e6 | 80 | dotstr.sum += mysum; |
cnhzcy14 | 0:fba50ae123e6 | 81 | printf("Thread %ld did %d to %d: mysum=%f global sum=%f\n",offset,start,end,mysum,dotstr.sum); |
cnhzcy14 | 0:fba50ae123e6 | 82 | osMutexRelease(stdio_mutex); |
cnhzcy14 | 0:fba50ae123e6 | 83 | |
cnhzcy14 | 0:fba50ae123e6 | 84 | id = osThreadGetId(); |
cnhzcy14 | 0:fba50ae123e6 | 85 | osThreadTerminate(id); |
cnhzcy14 | 0:fba50ae123e6 | 86 | } |
cnhzcy14 | 0:fba50ae123e6 | 87 | |
cnhzcy14 | 0:fba50ae123e6 | 88 | void t0(void const *argument) {dotprod(argument);} |
cnhzcy14 | 0:fba50ae123e6 | 89 | osThreadDef(t0, osPriorityNormal, DEFAULT_STACK_SIZE); |
cnhzcy14 | 0:fba50ae123e6 | 90 | |
cnhzcy14 | 0:fba50ae123e6 | 91 | void t1(void const *argument) {dotprod(argument);} |
cnhzcy14 | 0:fba50ae123e6 | 92 | osThreadDef(t1, osPriorityNormal, DEFAULT_STACK_SIZE); |
cnhzcy14 | 0:fba50ae123e6 | 93 | |
cnhzcy14 | 0:fba50ae123e6 | 94 | void t2(void const *argument) {dotprod(argument);} |
cnhzcy14 | 0:fba50ae123e6 | 95 | osThreadDef(t2, osPriorityNormal, DEFAULT_STACK_SIZE); |
cnhzcy14 | 0:fba50ae123e6 | 96 | |
cnhzcy14 | 0:fba50ae123e6 | 97 | void t3(void const *argument) {dotprod(argument);} |
cnhzcy14 | 0:fba50ae123e6 | 98 | osThreadDef(t3, osPriorityNormal, DEFAULT_STACK_SIZE); |
cnhzcy14 | 0:fba50ae123e6 | 99 | |
cnhzcy14 | 1:1308d7d6d53e | 100 | /* |
cnhzcy14 | 1:1308d7d6d53e | 101 | * The main program creates threads which do all the work and then |
cnhzcy14 | 1:1308d7d6d53e | 102 | * print out result upon completion. Before creating the threads, |
cnhzcy14 | 1:1308d7d6d53e | 103 | * The input data is created. Since all threads update a shared structure, we |
cnhzcy14 | 1:1308d7d6d53e | 104 | * need a mutex for mutual exclusion. The main thread needs to wait for |
cnhzcy14 | 1:1308d7d6d53e | 105 | * all threads to complete, it waits for each one of the threads. We specify |
cnhzcy14 | 1:1308d7d6d53e | 106 | * a thread attribute value that allow the main thread to join with the |
cnhzcy14 | 1:1308d7d6d53e | 107 | * threads it creates. Note also that we free up handles when they are |
cnhzcy14 | 1:1308d7d6d53e | 108 | * no longer needed. |
cnhzcy14 | 1:1308d7d6d53e | 109 | */ |
cnhzcy14 | 1:1308d7d6d53e | 110 | int main() |
cnhzcy14 | 1:1308d7d6d53e | 111 | { |
cnhzcy14 | 0:fba50ae123e6 | 112 | debug.baud(57600); |
cnhzcy14 | 0:fba50ae123e6 | 113 | |
cnhzcy14 | 0:fba50ae123e6 | 114 | long i; |
cnhzcy14 | 0:fba50ae123e6 | 115 | double *a, *b; |
cnhzcy14 | 0:fba50ae123e6 | 116 | |
cnhzcy14 | 0:fba50ae123e6 | 117 | /* Assign storage and initialize values */ |
cnhzcy14 | 0:fba50ae123e6 | 118 | a = (double*) malloc (NUMTHRDS*VECLEN*sizeof(double)); |
cnhzcy14 | 0:fba50ae123e6 | 119 | b = (double*) malloc (NUMTHRDS*VECLEN*sizeof(double)); |
cnhzcy14 | 0:fba50ae123e6 | 120 | |
cnhzcy14 | 1:1308d7d6d53e | 121 | for (i=0; i<VECLEN*NUMTHRDS; i++) |
cnhzcy14 | 1:1308d7d6d53e | 122 | { |
cnhzcy14 | 1:1308d7d6d53e | 123 | a[i]=1; |
cnhzcy14 | 1:1308d7d6d53e | 124 | b[i]=a[i]; |
cnhzcy14 | 1:1308d7d6d53e | 125 | } |
cnhzcy14 | 0:fba50ae123e6 | 126 | |
cnhzcy14 | 0:fba50ae123e6 | 127 | dotstr.veclen = VECLEN; |
cnhzcy14 | 0:fba50ae123e6 | 128 | dotstr.a = a; |
cnhzcy14 | 0:fba50ae123e6 | 129 | dotstr.b = b; |
cnhzcy14 | 0:fba50ae123e6 | 130 | dotstr.sum=0; |
cnhzcy14 | 0:fba50ae123e6 | 131 | |
cnhzcy14 | 0:fba50ae123e6 | 132 | stdio_mutex = osMutexCreate(osMutex(stdio_mutex)); |
cnhzcy14 | 0:fba50ae123e6 | 133 | |
cnhzcy14 | 1:1308d7d6d53e | 134 | /* Create threads to perform the dotproduct */ |
cnhzcy14 | 0:fba50ae123e6 | 135 | for(i=0;i<NUMTHRDS;i++) |
cnhzcy14 | 0:fba50ae123e6 | 136 | { |
cnhzcy14 | 1:1308d7d6d53e | 137 | /* Each thread works on a different set of data. |
cnhzcy14 | 1:1308d7d6d53e | 138 | * The offset is specified by 'i'. The size of |
cnhzcy14 | 1:1308d7d6d53e | 139 | * the data for each thread is indicated by VECLEN. |
cnhzcy14 | 1:1308d7d6d53e | 140 | */ |
cnhzcy14 | 0:fba50ae123e6 | 141 | if(i==0) osThreadCreate(osThread(t0), (void *)i); |
cnhzcy14 | 0:fba50ae123e6 | 142 | if(i==1) osThreadCreate(osThread(t1), (void *)i); |
cnhzcy14 | 0:fba50ae123e6 | 143 | if(i==2) osThreadCreate(osThread(t2), (void *)i); |
cnhzcy14 | 0:fba50ae123e6 | 144 | if(i==3) osThreadCreate(osThread(t3), (void *)i); |
cnhzcy14 | 0:fba50ae123e6 | 145 | } |
cnhzcy14 | 0:fba50ae123e6 | 146 | |
cnhzcy14 | 0:fba50ae123e6 | 147 | printf ("Sum = %f \n", dotstr.sum); |
cnhzcy14 | 0:fba50ae123e6 | 148 | free (a); |
cnhzcy14 | 0:fba50ae123e6 | 149 | free (b); |
cnhzcy14 | 0:fba50ae123e6 | 150 | } |
cnhzcy14 | 0:fba50ae123e6 | 151 | |
cnhzcy14 | 0:fba50ae123e6 | 152 |