[ home ] [ math / cs / ai / phy / as / chem / bio / geo ] [ civ / aero / mech / ee / hdl / os / dev / web / app / sys / net / sec ] [ med / fin / psy / soc / his / lit / lin / phi / arch ] [ off / vg / jp / 2hu / tc / ts / adv / hr / meta / tex ] [ chat ] [ wiki ]

Viewing source code

The following is the source code for post >>>/os/3

\textbf{Thread synchronization}
So the code in the OP successfully creates two threads and allows them to run concurrently. However, they are overcompetitive and print as many characters as they can as soon as they get the opportunity. The scheduler grants a certain execution time to every thread but it's not always fair. For example, it can give longer time to thread A compared to thread B, leading to large string of "aaaaaaaaaaaa...".

How would we make the two threads agree to  print e.g. "abababababab"?  The basic idea is as following: Allow thread A to signal thread B and block itself, and allow thread B to signal thread A and block itself. Thus, we'll A and B will alternate between blocking and signaling each other.

Using semaphores, we'll have semaphore \`sa = 1\` and semaphore \`sb = 0\` (two semaphores in total). Thread B will immediatelly attempt to decrement the semaphore \`sb\` thus block itself because the value of the semaphore zero. Thread A will successfully decrement \`sa\` from 1 to 0, but it will block itself in the next iteration - but not before it unblocks Thread B on semaphore \`sb\`. Thread B will then unblock A, and the process repeats.


POSIX semaphore initialization:
```
sem_t sa, sb;
int main() {
    sem_init(&sa, 0, 1);
    sem_init(&sb, 0, 0);
    ...
    sem_destroy(&sa);
    sem_destroy(&sb);
    return 0;
}
```
Thread A:
```
void* a(void* data) {
    for ( ; ; ) {
        sem_wait(&sa);
        printf("a");
        sem_post(&sb);
    }
    return NULL;
}
```
Thread B:
```
void* b(void* data) {
    for ( ; ; ) {
        sem_wait(&sb);
        printf("b")
        sem_signal(&sa);
    }
    return NULL;
}
```
We can also protect outselves against errors using \`assert()\` and also add some colors through \href{https://en.wikipedia.org/wiki/ANSI_escape_code}{ANSI escape codes}. ;)

The full code:
```
// main.c
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <assert.h>

#define RED "\e[31m"
#define GREEN "\e[32m"
#define NOCOLOR "\e[0m"

sem_t sa, sb;
void* a(void* data)
{
    for ( ; ; ) {
        assert(sem_wait(&sa) == 0);
        printf(RED "a" NOCOLOR);
        assert(sem_post(&sb) == 0);
    }
    return NULL;
}

void* b(void* data)
{
    for ( ; ; ) {
        assert(sem_wait(&sb) == 0);
        printf(GREEN "b" NOCOLOR);
        assert(sem_post(&sa) == 0);
    }
    return NULL;
}

int main()
{
    assert(sem_init(&sa, 0, 0) == 0);
    assert(sem_init(&sb, 0, 1) == 0);
    pthread_t ta, tb;
    assert(pthread_create(&ta, NULL, a, NULL) == 0);
    assert(pthread_create(&tb, NULL, b, NULL) == 0);
    assert(pthread_join(ta, NULL) == 0);
    assert(pthread_join(tb, NULL) == 0);
    assert(sem_destroy(&sa) == 0);
    assert(sem_destroy(&sb) == 0);
    return 0;
}
```

Compile with \`gcc -pthread main.c\` and run with  \`./a.out\`. Cancel with \`Ctrl + C\`