POSIX Threads

pthread and mutex

What’s thread management?
What’s mutexes?
What’s condition variables?
What’s synchronization?
Before answering to that, I will trace a code first: pthread.c
First, target at the main function to understand the purpose of this program:

pthread_t pid1, pid2;
pthread_create(&pid1,NULL,&add1,NULL);
pthread_create(&pid2,NULL,&add2,NULL);
pthread_join(pid1,NULL);
pthread_join(pid2,NULL);
printf("All threads finished\n");

With pthread_create(&pid1,NULL,&add1,NULL), I can create a thread to execute the add1() function. With pthread_join(pid1,NULL), main thread would wait for pid1 to finished. Here, we can know that the program create two threads to execute individual functions, and main thread waits for them to run. So, next we can trace to add1() and add2().
Here is a point what I need to notice about is the order of pthread_join()

pthread_join(pid1,NULL);
pthread_join(pid2,NULL);

This means pid2 will run ealier than pid1, but when we trace into the add2:

if(countt < ph1 || countt > ph2){
	pthread_cond_signal(&condition);   // our countt is still 0 currently
}else{
	xxxxx;

Because of the condition, pid2 will turn to wake up pid1
Then, we can see what pid1 does in add1:

// pid1
	for(;;){
		pthread_mutex_lock(&count);
		printf("here is %d\n",exe++);
		pthread_cond_wait(&condition,&count);

We have a global variable countt to be shared in two threads. To deal with race condition, we need avoid countt to be used at the same time. Therefore, pthread_mutex_lock(&count) can help us lock the mutex (&count), then the global variable countt can only be used in pid1 now. The function of pthread_cond_wait is important that he will release mutex, go to sleep with waiting signal.
Third, with pthread_cond_wait waiting for the signal, pid2 starts working:

// pid2
	for(;;){
		pthread_mutex_lock(&count);
		if(countt<ph1 || countt>ph2){
			pthread_cond_signal(&condition);
		}else{

After pid2 starts working, he also need to lock the mutex again and get into the condition. Currently, countt is still less than ph1, so pid2 will run the function of pthread_cond_signal. This function releases mutex, and sends signal to pid1.

// pid1
		countt++;
		printf("pid1's counter is %d\n",countt);
		pthread_mutex_unlock(&count);
		if(countt >= phase)
			return NULL;
	}

Therefore, pid1 continues the following work that adds 1 to countt, and unlocks the mutex for pid2. Then here comes a part which needs notices. When pid2 runs to pthread_cond_signal again, he will release mutex and send signal to wake pid1 up. At the same time, pid1 is stopped at the step before pthread_mutex_lock(&count);. So, when pid2 release the mutex, pid1 can lock on the mutex and start working. To make sure the footprint of execution, the code of printf("here is %d\n",exe++); helps me show that pid1 runs from lock again. The following is the running results of program:

Sorry for that the var name of condition variable and mutex will make you confusion. We need to trace the code with imagining that add1 and add2 run at the same time. Also be careful that the compiling way of pthread.c

Conclusion

Here I would like to emphasize on my part of printf('here is %d in add1\n',exe++); in add1() and printf('***') in add2. Thread management, is the whole process of routine that work directly on threads. Mutex, which is the abbreviation of “mutual exclusion” is used to solve the conflict on condition variables. In this example, condition variable is countt, and mutex is count. Unix system use mechanism of synchronization to deal with race condition.

Reference

George Mason University 201810.13237 CS-531-P01