Threads
Before starting, download this archive.
Warm up
HelloWorld! HelloWorld! HelloWorld! HelloWorld!
Write the program hello_pthread.c which creates 4 threads. Each thread displays "Hello World!".
The main thread, after creating the threads, waits for their termination.
Throughout the class, we will work on a "fil rouge" project inspired by a real case. It sets up a web server that hosts a social network such as Facebook.
To start, get the server database:
- git clone -b tp1_base https://gitlab.inf.telecom-sudparis.eu/csc4508/csc4508_facebook.git
This code base is composed of:
- main.c: launches the server with the parameters chosen by the user;
- server.c: receives HTTP requests and network connections;
- process_requests.c : process the requests: depending on the page requested, a response (i.e. HTML) is generated to be displayed in the user's browser.
Testing the Facebook server
After compiling the server, start it with ./server -p 8080, and connect from a web browser to the address http://localhost:8080.
using threads
The handle_get function is called each time a client requests a page. Depending on the page requested, the processing may be long and delay the processing of other incoming requests .
Modify the handle_get function so that it creates a new thread responsible for processing the request. Remember to detach the thread (man pthread_attr_setdetachstate) so that its resources are automatically free when it finished.
thread-safety
Since client requests are handled by different threads, the processing performed must be able to be done concurrently.
Analyze the source code to determine the shared data structures, and protect them using a mutex or atomic operations.
Debugging a multi-threaded program
The exo-gdb.c program creates 4 threads which each write a message ("Hello from thread x") in one of the slots of the array. After the termination of the threads, the main thread displays the contents of the table.
We would expect that the program displays:
Run the program and see that it does not display what we expect.
To determine the cause of the problem, let's use gdb (to help you, the main useful commands for gdb are grouped here ):
- Load the program into gdb (you may have need to modify the Makefile and add -g to the compilation flags, so that the debug symbols are included in the executable)
- Add a breakpoint at line 11, then run the program.
- Once the breakpoint is reached, print the source code located around the breakpoint, and display the variable values.
- Display the backtrace of the current thread.
- Display the list of threads, then for each threads, display the values of the variables. You should notice a problem. Fix the problem.
It is necessary to add the option -g in the CFLAGS of the Makefile.
Threads 2 and 3 have the same identifier my_id! When examining the code, we see that the value of my_id is calculated from i. There is a race condition: between the call to pthread_create and the instruction my_id = * (int *)arg, the value of i may change!
To fix this problem, a solution can be to create an array in which we store the arguments:
Mr and Mrs
In this exercise, we propose to write a "Mr. and Mrs." server:
- the client reads, on their command line, the name of family of "Mr. and Mrs." It sends it to the server.
- the server looks for this name in the file mEtMme.txt :
- if found, it returns the name of the son, the daughter or the many children;
- otherwise it returns the message "Sorry, I do not know";
- the client displays the message received from the server.
To do this, you have a client / server architecture in which:
- the client opens a message queue whose name is a function of its pid (so as not to interfere with other clients).
- the client connects to the server via another message queue (defined by the server).
- the client's request contains not only the "Mr. and Mrs.", but also the name of the message queue which was created in 1. by the client and on which the client waits for the response from the server.