详解Linux多线程使用信号量同步

2019-10-13 19:13:32王振洲

重新编译程序,此时运行结果如下:

当我们输入TEST时,主线程向子线程提供了两个输入,一个是来自键盘的输入,一个来自主线程复数据到msg中,然后从运行结果可以看出,运行出现了异常,没有处理和统计从键盘输入TEST的字符串而却对复制的数据作了两次处理。原因如上面所述。

五、解决此缺陷的方法

解决方法有两个,一个就是再增加一个信号量,让主线程等到子线程处理统计完成之后再继续执行;另一个方法就是使用互斥量。

下面给出用增加一个信号量的方法来解决该问题的代码,源文件名为semthread2.c,源代码如下:

#include <unistd.h> 
#include <pthread.h> 
#include <semaphore.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
 
 
//线程函数 
void *thread_func(void *msg); 
sem_t sem;//信号量 
sem_t sem_add;//增加的信号量 
 
 
#define MSG_SIZE 512 
 
 
int main() 
{ 
  int res = -1; 
  pthread_t thread; 
  void *thread_result = NULL; 
  char msg[MSG_SIZE]; 
  //初始化信号量,初始值为0 
  res = sem_init(&sem, 0, 0); 
  if(res == -1) 
  { 
    perror("semaphore intitialization failedn"); 
    exit(EXIT_FAILURE); 
  } 
  //初始化信号量,初始值为1 
  res = sem_init(&sem_add, 0, 1); 
  if(res == -1) 
  { 
    perror("semaphore intitialization failedn"); 
    exit(EXIT_FAILURE); 
  } 
  //创建线程,并把msg作为线程函数的参数 
  res = pthread_create(&thread, NULL, thread_func, msg); 
  if(res != 0) 
  { 
    perror("pthread_create failedn"); 
    exit(EXIT_FAILURE); 
  } 
  //输入信息,以输入end结束,由于fgets会把回车(n)也读入,所以判断时就变成了“endn” 
  printf("Input some text. Enter 'end'to finish...n"); 
   
  sem_wait(&sem_add); 
  while(strcmp("endn", msg) != 0) 
  { 
    if(strncmp("TEST", msg, 4) == 0) 
    { 
      strcpy(msg, "copy_datan"); 
      sem_post(&sem); 
      //把sem_add的值减1,即等待子线程处理完成 
      sem_wait(&sem_add); 
    } 
    fgets(msg, MSG_SIZE, stdin); 
    //把信号量加1 
    sem_post(&sem); 
    //把sem_add的值减1,即等待子线程处理完成 
    sem_wait(&sem_add); 
  } 
 
 
  printf("Waiting for thread to finish...n"); 
  //等待子线程结束 
  res = pthread_join(thread, &thread_result); 
  if(res != 0) 
  { 
    perror("pthread_join failedn"); 
    exit(EXIT_FAILURE); 
  } 
  printf("Thread joinedn"); 
  //清理信号量 
  sem_destroy(&sem); 
  sem_destroy(&sem_add); 
  exit(EXIT_SUCCESS); 
} 
 
 
void* thread_func(void *msg) 
{ 
  char *ptr = msg; 
  //把信号量减1 
  sem_wait(&sem); 
  while(strcmp("endn", msg) != 0) 
  { 
    int i = 0; 
    //把小写字母变成大写 
    for(; ptr[i] != ''; ++i) 
    { 
      if(ptr[i] >= 'a' && ptr[i] <= 'z') 
      { 
        ptr[i] -= 'a' - 'A'; 
      } 
    } 
    printf("You input %d charactersn", i-1); 
    printf("To Uppercase: %sn", ptr); 
    //把信号量加1,表明子线程处理完成 
    sem_post(&sem_add); 
    //把信号量减1 
    sem_wait(&sem); 
  } 
  sem_post(&sem_add); 
  //退出线程 
  pthread_exit(NULL);