Talk C chestnuts together (114th back: C language instance-semaphores for thread synchronization)
Hello, the last time we talked aboutSemaphores for Thread Synchronization. When you leave the rest of your time, your words will go right. Let's talk C chestnuts together!
We described in detail the usage of semaphores-related functions in the last time. In this time, we introduced how to use these functions to operate semaphores.
The procedure is as follows:
1. defines A semaphore A to synchronize threads. 2. use the sem_init function in the thread creation process to initialize the semaphore A value to 0; 3. use sem_wait in the thread for Data Reading to implement P operations; 4. modify the data in the data writing thread. After the Data Writing operation is complete, use sem_post to implement the V operation. 5. use the sem_destroy function to release resources related to semaphores in the thread creation process;
The readers will not write the code in the text, and the detailed code will be put into my resources. You can download and use it.
In the code, we implement the function of reading/writing data by ourselves.Both functions use delayed operations to demonstrate that it takes some time to read or write data..
This may occur when the program is running:
If the read operation is not completed, the write operation is started. This will cause the data read by the read operation to be inaccurate. If the write operation is not completed, the read operation will begin, this will result in inaccurate data read by the read operation;
Void read_data (char * str) {printf ("[% s] start reading data \ n", str); sleep (1 ); // delay operation printf ("[% s] data = % d \ n", str, data); // read data, and display data printf ("[% s] end reading data \ n", str );}
Void write_data (char * str) {printf ("[% s] start writing data \ n", str); sleep (1); // delay operation data ++; // printf ("[% s] data = % d \ n", str, data) for data process write operations ); printf ("[% s] end writing data \ n", str );}
The following is the running result of the program. For details, refer:
Create first thread // Create the first thread Create second Thread // Create the second thread ID :: 3076148032 ----------- S ---------- [Thread_1] start reading data // The first Thread starts to read data (the first operation on data is a read operation) Thread ID :: 3067755328 ----------- S ---------- [Thread_2] start writing data // The second thread starts writing data [Thread_1] data = 0 // The write operation is not completed yet, the data read by the first thread is the initial value [Thread_1] end reading data [Thread_1] start reading data [Thread_2] data = 1 [Thread_2] end writing data // The write operation is completed, the second thread modifies the data to 1 [Thread_1] data = 1 // The write operation is complete, the data read by the first thread is the data modified by the write operation [Thread_1] end reading data [Thread_1] start reading data [Thread_2] start writing data [Thread_1] data = 1 [Thread_1] end reading data Thread ID:: 3076148032 ----------- E ---------- // The end Of The thread for reading data [Thread_2] data = 2 [Thread_2] end writing data [Thread_2] start writing data [Thread_2] data = 3 [Thread_2] end writing data [Thread_2] start writing data [Thread_2] data = 4 [Thread_2] end writing data Thread ID:: 3067755328 ----------- E ---------- // end of Data Writing
As you can see from the above results, if the data read operation is not completed, the write operation starts to run, or the write operation is not completed, and the read operation starts to run. In short, read operations and write operations run in a mix, and the data displayed by read operations in the program is not accurate.
We add a semaphore to the program according to the above operation steps, and use the semaphore to achieve thread synchronization. To facilitate operations in the code, you only need to remove the comments before the macro definition code:
// # Define SEM_ENABLE 1
Because we use macros to control semaphores in the Code, the details are as follows:
#ifdef SEM_ENABLE res = sem_wait(&sem_value); if(res != 0) { printf(" sem wait failed \n"); }#endif
#ifdef SEM_ENABLE res = sem_post(&sem_value); if(res != 0) { printf(" sem post failed \n"); }#endif
The following is the running result of the program after the semaphore synchronization thread is used. For details, refer:
Create first thread // Create the first thread Create second Thread // Create the second Thread thread ID: 3075992384 ----------- S ---------- thread ID :: 3067599680 ----------- S ---------- [Thread_2] start writing data // The second thread starts writing data (the first operation on data is a write operation) [Thread_2] data = 1 [Thread_2] end writing data // The data write operation in the second thread has completed [Thread_1] start reading data // The first thread starts to read data [Thread_1] data = 1 [Thread_1] end reading data // The data reading operation in the first thread has completed [Thread_2] start writing data [Thread_2] data = 2 [Thread_2] end writing data [Thread_1] start reading data [Thread_1] data = 2 [Thread_1] end reading data [Thread_2] start writing data [Thread_2] data = 3 [Thread_2] end writing data [Thread_1] start reading data [Thread_1] data = 3 [Thread_1] end reading data [Thread_2] start writing data [Thread_2] data = 4 [Thread_2] end writing data Thread ID:: 3075992384 ----------- E ---------- // end of the Thread for reading data Thread ID: 3067599680 ----------- E ---------- // end of the Thread for writing data
From the preceding running results, we can see that after synchronizing two threads using semaphores, the Data Reading thread and the Data Writing thread run in sequence: write data before reading data. This ensures that the read data is accurate.
In addition, you can see that the main process first creates a thread to read data, and then creates a thread to write data. Therefore, you should first read the data before writing the data. However, because we use semaphores to synchronize threads, when the program is running, we first execute the write operation before executing the read operation. Therefore, in the running result, the first operation on data is a write operation. This can be compared with the program running results without using semaphores.
Let's talk about the semaphores for thread synchronization. I want to know what examples will be provided later, and I will try again.