[ 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/1

\textbf{What is threading?}
Consider a function that contains an  infinite loop:
```
void* a(void* data)
{
    for ( ; ; ) {
        printf("a");
    }
    return NULL;
}
```
Calling the function \`a();\` would cause the program to print "a" forever.

Now consider another function with an infinite loop: 
```
void* b(void* data) 
{
    for ( ; ; ) {
        printf("b");
    }
    return NULL;
}
```
Calling the function \`b();\`, it would cause the program to print "b" forever. 

What if we were to consecutively call \`a(); b();\`? Well, since \`a()\` contains an infinite loop, the call to \`b()\` is never going to happen, so all we're going to get is "aaaaaaaaaaaaaaaa". Similarly, if we were to call \`b(); a();\` all we're going to get is "bbbbbbbbbbbbbbbbb".  Is there a way to make the program print a little bit of "a" and a little bit of "b" (i.e. "aaaabbbbbbbaaabbbb") without changing the code (i.e. with infinite loops)? This is what threads are about. By creating threads, we make it possible for multiple infinite loops to execute concurrently. Note that there is a slight difference between \textbf{concurrency} and \textbf{parallelism}. Parallel execution means two tasks are running completely simultaneously. Concurrent execution means two tasks are switching turns: task 1 is executing, then task 2, then task 1 again... If context switching is happening fast enough (the OS scheduler is the one deciding this), it would appear as if though they were running in parallel. Most synchronization techniques work the same for both so we'll make no distinction.


By default, every program is single-threaded and the only thread running is the one executing the \`main()\` function. We can create more threads by calling \`pthread_create()\` and passing the pointer to a callback function (\`void* (*cb)(void*);\`). If we create two threads - one for function \`a()\` and one for function \`b()\` - we will end up with three threads: 

\begin{itemize}
\item Thread executing a()
\item Thread executing b()
\item Thread executing main()
\end{itemize}
Once threads are created they are marked as , the scheduler will grant them the opportunity to execute at some point. The \`main()\` thread, on the other hand, is just going to continue its execution as normal. If the main thread encounters \`return 0;\` the operating system is going to kill the program along with all the threads started. To prevent this from happening, we can use \`pthread_join()\` to tell the main thread to wait for other threads to finish. Since other threads contain infinite loops, they are never going to finish. The to thread joining was putting an infinite loop in the main function just after thread creation. Most pthread functions return 0 upon success and a value smaller than 0 upon error. We can use \`assert()\` as a rudimentary runtime error check. 

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

void* a(void* data)
{
    for ( ; ; ) {
        printf("a");
    }
    return NULL;
}

void* b(void* data) 
{
    for ( ; ; ) {
        printf("b");
    }
    return NULL;
}

int main()
{
    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);
    return 0;
}
```
Compiling the code above with \`gcc -pthread main.c\` and running it with \`./a.out\` should print "aaaabbbbbaaaabbbbb". Since the program will never terminate, it can be interrupted with \`Ctrl+C\` which is going to send \`SIGINT\` to the program which, by default, will make it terminate.