Basics of multithreading in C
Nathanael Demacon
Updated on
・3 min read
C is a language that runs on one thread by default, which means that the code will only run one instruction at a time. In some cases you'll need to do multiple instructions at a time, a graphical interface for instance, will not stop when it performs an action related to a button's click. That's what we call multithreading, not to be confused with asynchronous operations that can be performed in only one thread that does multiple tasks.
What is a thread?
A thread is a task that runs linked to a process. A process we can have multiple threads and threads can run other threads and so on.
By default a process runs on a single thread. Each thread is new tasks that can be run indefinitely and in parallel to the other threads.
Creating a thread
Like said in the title, this post will talk about multithreading in C, so we will do C!
On POSIX operating systems, there is a library named
pthread.h, which does exactly what it says, create threads! To use it under compilers, you'll need to link it with
-lpthread argument (ex:
gcc -lpthread main.c).
#include <pthread.h> #include <unistd.h> #include <stdio.h> void wait(void) { sleep(2); printf("Done.\n"); } int main(void) { pthread_t thread; int err; err = pthread_create(&thread, NULL, wait, NULL); if (err) { printf("An error occured: %d", err); return 1; } printf("Waiting for the thread to end...\n"); pthread_join(thread, NULL); printf("Thread ended.\n"); return 0; }
The output will be:
Waiting for the thread to end... Done. (~2 seconds after) Thread ended.
The main thread continued and printed a message while the created thread was operating and it's only one line to call a function in a new thread, pretty easy for C uh? Maybe you're a little lost, I will explain the code.
First of all, we include the
pthread.h library, like said above, it contains all the functions needed to perform multithreading tasks. Then we include
unistd.h which is containing the
sleep() function. And then the
stdio.h for
printf().
pthread_create function is called to create the thread. It requires a
pthread_t, which is the thread descriptor, a pointer to a
void function and some other parameters that I will not describe here, the function's arguments for instance.
pthread_join is used to link the current thread process to another thread. It literally makes the program stops in order to wait for the end of the selected thread.
Mutex
Doing multiple operations on one target at the same time is very dangerous, the best example I can give is for databases. If three threads want to write a single file at the same time, it would be a problem because an hard drive can't go as fast as a CPU does. In this case we should lock the other threads in order to not overload the hard drive with tasks that can corrupt the file. Mutex can be used to lock the other threads.
In practice, we use mutex to tell if the task is locked or unlocked.
#include <pthread.h> #include <unistd.h> #include <stdio.h> pthread_mutex_t lock; int j; void do_process() { pthread_mutex_lock(&lock); int i = 0; j++; while(i < 5) { printf("%d", j); sleep(1); i++; } printf("...Done\n"); pthread_mutex_unlock(&lock); } int main(void) { int err; pthread_t t1, t2; if (pthread_mutex_init(&lock, NULL) != 0) { printf("Mutex initialization failed.\n"); return 1; } j = 0; pthread_create(&t1, NULL, do_process, NULL); pthread_create(&t2, NULL, do_process, NULL); pthread_join(t1, NULL); pthread_join(t2, NULL); return 0; }
The output will be:
111111...Done 222222...Done. The notion of ownership is not present in the case of a semaphore, so they can be locked and unlocked by any part of the program.
That was pretty easy don't you think? C functions are very powerful to perform such actions, a great power carries a great responsibility.
Solving Puzzles With High-Performance JavaScript
Premature optimization is the root of all evil. It's also the root of this article. I like programmi...
pthread is outdated since availability of C11 which introduced standard threading in C. The header files is
<threads.h>with functions like
thrd_create.
The standard functions for threading, conditions, and signalling, provide guarantees that pthreads cannot.
I have my answers,
threads.his better to use even if it's not POSIX (stackoverflow.com/a/9377007)
pthread.his POSIX compliant,
threads.hisn't.
But sure you can use it, it's implemented in linux and freeBSD kernels.
But
threads.his C11 compliant so by now ALL compilers have support for C11 at least for the three major ones:
MSVC
GCC
CLANG
Yup, seems nice, their is just a lack of documentation, I wanted to know what did it really does.
You can find documentation here: en.cppreference.com/w/c/thread
Well, it's the C libraries for two of those platforms that are supposed to implement
threads.h(even though I'm pretty sure glibc doesn't), although I'm not sure what Windows does.
It's not the kernels, it's the C libraries. You can have a kernel installed and not be able to do anything without a C library.
Thanks Nathanael! Nice starter article on pthreads :)
For the curious, Lawrence Livermore National Laboratory have this article with more background and examples of why you might use the various features available in pthreads: computing.llnl.gov/tutorials/pthre...
It's also a good idea to make sure you are using thread-safe library functions, here's a nice SO question and answer: stackoverflow.com/questions/125957...
Enjoy your full control of the CPU!
Glab that you enjoyed it!
I'm starting to understand a lot about pure Computer Science since I got some courses about the theory of operating systems. It's so fascinating to learn how things really works beyond the compilers and why things are like that in programming languages!
Can you suggest that courses pls.
For the theory of operating systems, I see this subject at my school (engineering school), but for programming languages I heard that Engineering a Compiler is very great when starting in this domain.
The Dragon Book is very good but much more advanced.
Thank god for every C-related article here (for us, who have interest in low-level programming). Thanks, Nathanael!
C can be a very scary language at first but it's so captivating, I'm happy that you enjoyed reading this article 😄
Why can't you use a
forloop?
for( i = 0; i < 5; i++ )
You can and should do a for loop. It's been 1 year since I did this article, I think it's time to rewrite it with my current knowledge :)