Detailed Linux multithreading using signal synchronization _linux

Source: Internet
Author: User
Tags lowercase semaphore stdin strcmp

Semaphore, sync these nouns have been said in the process of communication, where they mean the same, except that the synchronized objects are different. However, the interface of the semaphore described below is used for the semaphore of the thread, and attention should not be confused with the semaphore used for interprocess communication.

One, what is the signal quantity

A thread's semaphore is the same as the semaphore used in interprocess communication, it is a special variable that can be added or reduced, but critical access to it is guaranteed to be atomic. If more than one thread in a program tries to change the value of a semaphore, the system guarantees that all operations will proceed sequentially.

and only 0 and 12 of the value of the signal is called binary semaphore, here will be highlighted. Semaphores are generally used to protect a piece of code, which is run by only one thread at a time. We can use binary semaphore to do this work.

interface and use of signal quantity

The semaphore functions begin with Sem_, with 4 of the basic semaphore functions used in the thread, all of which are declared in the header file semaphore.h.

1. Sem_init function

This function is used to create semaphores, and its prototype is as follows:

int Sem_init (sem_t *sem, int pshared, unsigned int value); 

The function initializes the signal object that the SEM points to, sets its share option, and gives it an initial integer value. Pshared control the type of semaphore, if its value is 0, it means that the signal is the current process of the local signal, otherwise the semaphore can be shared between several processes, value is the initial value of SEM. When the call succeeds, it returns 0, and the failure returns-1.

2. sem_wait function

This function is used to reduce the value of the semaphore by 1 in atomic operation. The atomic operation is that if two threads attempt to simultaneously give a semaphore 1 or minus 1, they do not interfere with each other. Its prototype is as follows:

int sem_wait (sem_t *sem); 

The object that the SEM points to is the semaphore initialized by the Sem_init call. When the call succeeds, it returns 0, and the failure returns-1.

3. Sem_post function

This function is used to add the semaphore value by 1 in atomic operation. Its prototype is as follows:

 
 

As with sem_wait, the object that SEM points to is the semaphore initialized by the Sem_init call. When the call succeeds, it returns 0, and the failure returns-1.

4. Sem_destroy function

This function is used to clean up the amount of semaphore used. Its prototype is as follows:

 
 

Returns 0 on success and 1 on failure.

Third, the use of signal synchronization thread

The following is a simple multithreaded program that shows how to use semaphores for thread synchronization. In the main thread, we create a child thread and pass the array msg as a parameter to the child thread, and then the main thread waits until there is text input and then calls Sem_post to increase the semaphore value, which immediately causes the child thread to return from the sem_wait wait and start execution. After the thread function turns the lowercase letter of the string into uppercase and counts the number of characters entered, it calls sem_wait again and is blocked again until the main thread calls the Sem_post to increase the semaphore value again.

#include <unistd.h> #include <pthread.h> #include <semaphore.h> #include <stdlib.h> #include 
<stdio.h> #include <string.h>/thread function void *thread_func (void *msg); 
  sem_t sem;//semaphore #define Msg_size int main () {int res =-1; 
  pthread_t thread; 
  void *thread_result = NULL; 
  Char Msg[msg_size]; 
  Initialize the semaphore, whose initial value is 0 res = sem_init (&sem, 0, 0); 
    if (res = = 1) {perror ("semaphore intitialization failed\n"); 
  Exit (Exit_failure); 
  ///create thread, and take msg as parameter of the thread function res = pthread_create (&thread, NULL, Thread_func, msg); 
    if (res!= 0) {perror ("pthread_create failed\n"); 
  Exit (Exit_failure); //input information to enter end, since Fgets will also read the carriage return (\ n), so the judgment becomes "end\n" printf ("Input some text.") 
  Enter ' End ' to finish...\n '); 
    while (strcmp ("end\n", msg)!= 0) {fgets (msg, msg_size, stdin); 
  Add the signal amount to 1 sem_post (&AMP;SEM); 
  printf ("Waiting for Thread to finish...\n"); Wait child thread End res = pthread_join (thread, &thread_result); 
    if (res!= 0) {perror ("Pthread_join failed\n"); 
  Exit (Exit_failure); 
  printf ("Thread joined\n"); 
  Clearing the signal volume Sem_destroy (&AMP;SEM); 
Exit (exit_success); 
  } void* Thread_func (void *msg) {//reduce semaphore by 1 sem_wait (&AMP;SEM); 
  char *ptr = msg; 
    while (strcmp ("end\n", msg)!= 0) {int i = 0; 
        Turn lowercase letters to uppercase for (; Ptr[i]!= ' n '; ++i) {if (Ptr[i] >= ' A ' && ptr[i] <= ' z ') { 
      Ptr[i]-= ' a '-' a '; 
    } printf ("You input%d characters\n", i-1); 
    printf ("To uppercase:%s\n", PTR); 
  Reduce the signal quantity by 1 sem_wait (&AMP;SEM); 
}//Exit thread Pthread_exit (NULL); 
 }

The results of the operation are as follows:

From the results of the operation, this program is indeed running at the same time two threads, one control input, the other control processing statistics and output.

Analysis of the shortcomings of this signal synchronization program

But this program has a little bit of a problem, that is, this program relies on receiving text input long enough, this way line Cheng have enough time before the main thread is not ready to give it more words to process and statistics before processing and counting the number of characters in the workspace. So when we quickly give it two different sets of words to count, the child thread does not have enough time to execute, but the semaphore has been incremented more than once, so the character statistics thread (the child thread) repeats and counts the number of characters and reduces the value of the semaphore until it becomes 0 again.

To better illustrate the situation above, modify the code in the while loop of the main thread as follows:

printf ("Input some text.") Enter ' End ' to finish...\n '); 
while (strcmp ("end\n", msg)!= 0) 
{ 
  if (strncmp ("TEST", MSG, 4) = 0) 
  { 
    strcpy (msg, "copy_data\n"); 
    Sem_post (&sem); 
  } 
  Fgets (msg, msg_size, stdin); 
  Add the signal amount to 1 
  sem_post (&SEM); 

Recompile the program, at which point the results are as follows:

When we enter test, the mainline Cheng thread provides two inputs, one from the keyboard input, one from the mainline Cheng data to MSG, and then from the results of the run, there is an exception, no processing and statistics on the string from the keyboard input test, while the replicated data is processed two times. The reason is as described above.

V. Ways to resolve this flaw

There are two solutions, one is to add another semaphore, so that the main thread wait until the child thread processing statistics completed before continuing execution, another method is to use the mutex.

The following is a code to solve the problem by adding a semaphore, the source file name is semthread2.c, and the source code is as follows:

#include <unistd.h> #include <pthread.h> #include <semaphore.h> #include <stdlib.h> #include 
<stdio.h> #include <string.h>/thread function void *thread_func (void *msg); 
  sem_t sem;//Signal Volume sem_t sem_add;//increased semaphore #define MSG_SIZE the int main () {int res =-1; 
  pthread_t thread; 
  void *thread_result = NULL; 
  Char Msg[msg_size]; 
  Initializes the semaphore with an initial value of 0 res = sem_init (&sem, 0, 0); 
    if (res = = 1) {perror ("semaphore intitialization failed\n"); 
  Exit (Exit_failure); 
  //init semaphore, initial value is 1 res = sem_init (&sem_add, 0, 1); 
    if (res = = 1) {perror ("semaphore intitialization failed\n"); 
  Exit (Exit_failure); 
  ///create thread, and take msg as parameter of the thread function res = pthread_create (&thread, NULL, Thread_func, msg); 
    if (res!= 0) {perror ("pthread_create failed\n"); 
  Exit (Exit_failure); //input information to enter end, since Fgets will also read the carriage return (\ n), so the judgment becomes "end\n" printf ("Input some text.") 
   
  Enter ' End ' to finish...\n '); SEm_wait (&sem_add); 
      while (strcmp ("end\n", msg)!= 0) {if (strncmp ("TEST", MSG, 4) = 0) {strcpy (msg, "copy_data\n"); 
      Sem_post (&sem); 
    Reduce the value of the Sem_add by 1, i.e. wait for the child thread to finish sem_wait (&sem_add); 
    Fgets (msg, msg_size, stdin); 
    Add the signal amount to 1 sem_post (&AMP;SEM); 
  Reduce the value of the Sem_add by 1, i.e. wait for the child thread to finish sem_wait (&sem_add); 
  printf ("Waiting for Thread to finish...\n"); 
  Wait child thread End res = pthread_join (thread, &thread_result); 
    if (res!= 0) {perror ("Pthread_join failed\n"); 
  Exit (Exit_failure); 
  printf ("Thread joined\n"); 
  Clearing the signal volume Sem_destroy (&AMP;SEM); 
  Sem_destroy (&sem_add); 
Exit (exit_success); 
  } void* Thread_func (void *msg) {char *ptr = msg; 
  Reduce the signal quantity by 1 sem_wait (&AMP;SEM); 
    while (strcmp ("end\n", msg)!= 0) {int i = 0; 
        Turn lowercase letters to uppercase for (; Ptr[i]!= ' n '; ++i) {if (Ptr[i] >= ' A ' && ptr[i] <= ' z ') { Ptr[i]-= ' a ' -' A '; 
    } printf ("You input%d characters\n", i-1); 
    printf ("To uppercase:%s\n", PTR); 
    The signal quantity is added 1, indicating that the threading process completes Sem_post (&sem_add); 
  Reduce the signal quantity by 1 sem_wait (&AMP;SEM); 
  } sem_post (&sem_add); 
 Exit thread Pthread_exit (NULL);

The results of the operation are as follows:

Analysis: Here we use a semaphore sem_add, and its initial value of 1, in the main thread in the use of sem_wait to wait for the child to process the complete, because its initial value is 1, so the main thread first call sem_wait always return immediately, The second call needs to wait for the child thread to finish processing. In a child thread, if the processing completes, the sem_post is used to increase the semaphore value, so that the sem_wait in the main thread immediately returns and executes the following code immediately. From the results of the operation, the operation is finally normal. Note that in the thread function, the semaphore SEM and Sem_add use the order of the sem_wait and Sem_post functions, their order can not be confused, otherwise, when the end is entered, may not run normally, the child thread can not exit normally, resulting in the program can not exit.

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.