2008-02-13 20:57:46 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2014-12-11 11:10:24 -05:00
|
|
|
#include <errno.h>
|
2010-05-26 19:38:11 +00:00
|
|
|
#include "Sleep.h"
|
2014-12-11 11:10:24 -05:00
|
|
|
#include "Thread.h"
|
2008-02-13 20:57:46 +00:00
|
|
|
|
2014-12-11 11:10:24 -05:00
|
|
|
static const int NUM_THREADS = 5;
|
2010-05-26 19:38:11 +00:00
|
|
|
|
2014-12-11 11:10:24 -05:00
|
|
|
struct PrintHelloArgs {
|
|
|
|
int thread_id;
|
|
|
|
ThreadBarrier *barrier_start;
|
|
|
|
ThreadBarrier *barrier_finish;
|
|
|
|
ThreadSemaphore *sem_start;
|
|
|
|
};
|
2010-05-26 19:38:11 +00:00
|
|
|
|
2014-12-11 11:10:24 -05:00
|
|
|
static ThreadRet THREAD_CALL_CONV PrintHello(void *void_arg)
|
2008-02-13 20:57:46 +00:00
|
|
|
{
|
2014-12-11 11:10:24 -05:00
|
|
|
struct PrintHelloArgs *args = (struct PrintHelloArgs *) void_arg;
|
|
|
|
int thread_id = args->thread_id;
|
|
|
|
ThreadBarrier *barrier_start = args->barrier_start;
|
|
|
|
ThreadBarrier *barrier_finish = args->barrier_finish;
|
|
|
|
ThreadSemaphore *sem_start = args->sem_start;
|
|
|
|
|
|
|
|
/* Indicate to main thread that the thread is started. */
|
|
|
|
ThreadSemaphorePut(sem_start);
|
|
|
|
|
|
|
|
printf("Hello World! It's me, thread #%d!\n", thread_id);
|
|
|
|
|
|
|
|
/* Make sure that all threads are started before the breakpoint in main hits. */
|
|
|
|
ThreadBarrierWait(barrier_start);
|
|
|
|
|
|
|
|
printf("Thread %d in the middle\n", thread_id);
|
|
|
|
|
|
|
|
/* Make sure that the thread does not finish before the breakpoint in main hits. */
|
|
|
|
ThreadBarrierWait(barrier_finish);
|
|
|
|
|
|
|
|
printf("Goodbye World! From thread #%d\n", thread_id);
|
|
|
|
|
|
|
|
return THREAD_DEFAULT_RET;
|
2008-02-13 20:57:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2014-12-11 11:10:24 -05:00
|
|
|
ThreadHandle threads[NUM_THREADS];
|
|
|
|
struct PrintHelloArgs args[NUM_THREADS];
|
|
|
|
|
|
|
|
/* Used to make rendez-vous points between all threads. */
|
|
|
|
ThreadBarrier barrier_start;
|
|
|
|
ThreadBarrier barrier_finish;
|
|
|
|
|
|
|
|
/* Used to tell when a thread is started for real. */
|
|
|
|
ThreadSemaphore sem_start;
|
|
|
|
|
|
|
|
/* + 1 for main thread */
|
|
|
|
ThreadBarrierInit(&barrier_start, NUM_THREADS + 1);
|
|
|
|
ThreadBarrierInit(&barrier_finish, NUM_THREADS + 1);
|
|
|
|
|
|
|
|
ThreadSemaphoreInit(&sem_start, 0);
|
|
|
|
|
|
|
|
for (int t = 0; t < NUM_THREADS; t++)
|
2010-05-26 19:38:11 +00:00
|
|
|
{
|
2014-12-11 11:10:24 -05:00
|
|
|
printf("In main: creating thread #%d\n", t);
|
|
|
|
|
|
|
|
args[t].thread_id = t;
|
|
|
|
args[t].barrier_start = &barrier_start;
|
|
|
|
args[t].barrier_finish = &barrier_finish;
|
|
|
|
args[t].sem_start = &sem_start;
|
|
|
|
|
|
|
|
int ret = StartThread(PrintHello, &args[t], &threads[t]);
|
|
|
|
|
|
|
|
if (!ret)
|
2010-05-26 19:38:11 +00:00
|
|
|
{
|
2014-12-11 11:10:24 -05:00
|
|
|
printf("Error: StartThread failed.\n");
|
2010-05-26 19:38:11 +00:00
|
|
|
exit(-1);
|
|
|
|
}
|
2014-12-11 11:10:24 -05:00
|
|
|
|
|
|
|
/* Wait until the thread has really started. */
|
|
|
|
ThreadSemaphoreTake(&sem_start);
|
|
|
|
|
|
|
|
printf("In main: thread #%d has started\n", t); /* Breakpoint LINE_MAIN_AFTER_THREAD_START */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Let the threads continue to the 'critical' section> */
|
|
|
|
ThreadBarrierWait(&barrier_start);
|
|
|
|
|
|
|
|
printf("In main thread, all threads created.\n"); /* main breakpoint here */
|
|
|
|
|
|
|
|
SLEEP(30);
|
|
|
|
|
|
|
|
/* Unlock the threads and let the program finish. */
|
|
|
|
ThreadBarrierWait(&barrier_finish);
|
|
|
|
|
|
|
|
for (int t = 0; t < NUM_THREADS; t++)
|
|
|
|
{
|
|
|
|
printf("In main, joining thread #%d\n", t);
|
|
|
|
JoinThread(threads[t], NULL);
|
2010-05-26 19:38:11 +00:00
|
|
|
}
|
2014-12-11 11:10:24 -05:00
|
|
|
|
|
|
|
ThreadBarrierDestroy(&barrier_start);
|
|
|
|
ThreadBarrierDestroy(&barrier_finish);
|
|
|
|
ThreadSemaphoreDestroy(&sem_start);
|
|
|
|
|
2010-05-27 21:20:45 +00:00
|
|
|
return 0;
|
2008-02-13 20:57:46 +00:00
|
|
|
}
|