/*
    This program provides a very small example of creating a thread, 
    and using a semaphore for the parent (main()) to synchronize with the
    child (my_function())

    It must be compiled using -lpthread
*/

#include <assert.h>
#include <semaphore.h>
#include <pthread.h>
#include <unistd.h>
#include <iostream>
using namespace std;

sem_t sem_mutex;
sem_t sem_print_mutex;

// printing to standard out is a critical section when there are 
// multiple threads -- thus must protect it with a semaphore
void print(char *str)
{
    int result = sem_wait(&sem_print_mutex);
    assert(!result);
    cout << str << endl;
    result = sem_post(&sem_print_mutex);
    assert(!result);
}

// code to be executed by the child thread 
void *my_function(void *arg)
{
    print("Hello from my_function()");
    int result;

    result = sem_wait(&sem_mutex);
    assert(!result);
    print("my_function() got sem_mutex");
    sleep(2); // simulate my_function() doing something
    print("Bye bye from my_function()");
}

int 
main()
{
    int result;
    result = sem_init(&sem_mutex, /* pshared = */ 0, /* value = */ 0);
    assert(!result);

    result = sem_init(&sem_print_mutex, /* pshared = */ 0, /* value = */ 1);
    assert(!result);

    print("Hello from main()");

    pthread_t my_thread;
    result = pthread_create(&my_thread, 0, my_function, /* arg = */ 0);
    assert(!result);

    print("main() after pthread_create() about to wake up my_thread");
    sleep(2);
    result = sem_post(&sem_mutex);
    assert(!result);

    result = pthread_join(my_thread, 0);
    assert(!result);

    print("main() after join...");
}

