Semaphore / Mutex和Printf之间的同步

时间:2016-12-30 15:55:53

标签: c printf mutex semaphore binary-semaphore

我正在为我的操作系统课程的信号量和同步工作(请参阅下面的粗体文字)。练习的内容是:

Pthread信号量和互斥量

  

C程序gen_binary_numbers.c在命令行上接收一个整数n,并使用递归生成并显示n位的所有二进制数。将递归程序转换为并发程序,将递归程序替换为生成显示二进制数的适当数量的进程(按任意顺序)。

这是我的代码,实际上是:

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>

int num, r, c;
pthread_mutex_t mutex;
void *genBin(void *arg);

int main (int argc, char **argv) {
  if (argc != 2) {
    fprintf(stdout, "\nUSAGE: %s <n>\n\n", argv[0]);
    exit(EXIT_FAILURE);
  }

  int i;
  num = atoi(argv[1]);
  c = num;
  r = 2;
  for (i=1; i<num; i++) {
    r=r*2;
  }

  pthread_mutex_init(&mutex, NULL);
  pthread_t* p;
  p = malloc(r*sizeof(pthread_t));

  for (i=0;i<r;i++) {
    if (pthread_create(&p[i], NULL, genBin, &i)) {
      fprintf(stderr, "Error creating thread.\n");
      exit(EXIT_FAILURE);
    }
  }
  pthread_exit(0);
}

void *genBin (void *arg) {
  int x;
  int i=0;
  x = *((int*)arg);

  pthread_mutex_lock(&mutex);

  while (i<num) {
    if(x!=0) {
      fprintf(stdout, "%d", x%2);
    }
    else {
      fprintf(stdout, "0");
    }
    i++;
    x/=2;
  }
  fprintf(stdout, "\n");
  pthread_mutex_unlock(&mutex);
  pthread_exit(0);
}

我认为代码应该返回正确的解决方案,但有时输出不会返回正确的数字。

正确输出的示例:

./genBin 3
100
101
010
110
001
011
111
000

输出错误的示例(由于重复):

./genBin 3
110
110
110
001
011
111
111
000

我认为问题在于互斥锁和printf之间的同步。 是否有其他解决方案可以避免混淆结果?

3 个答案:

答案 0 :(得分:1)

问题出在这一部分:

  for (i=0;i<r;i++) {
    if (pthread_create(&p[i], NULL, genBin, &i)) {
      fprintf(stderr, "Error creating thread.\n");
      exit(EXIT_FAILURE);
    }
  }

data race因为您将i的地址传递给所有线程。您可以使用临时数组将单个数字传递给每个线程。

答案 1 :(得分:1)

您的代码包含竞争条件。在main中,您将迭代变量i的地址作为线程函数的参数传递。然后每个新线程与主线程竞争,以在主线程递增之前读取i的值(通过提供的指针)。解决该问题的一种方法是在创建每个线程之后使用信号量使主线程等待,直到该线程取消引用其参数。

另外,我认为您不需要在genBin()中使用互斥锁。它访问的唯一共享数据是stdout,通过fprintf(),该函数的操作就像锁定与指定流关联的独占锁一样。此外,使用互斥锁基本上没有实际的并发性,因为每个线程几乎在执行的整个持续时间内都会锁定互斥锁。

答案 2 :(得分:0)

感谢大家!你解决了我的问题。这是更正后的代码:

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>

int num, r, c;
pthread_mutex_t mutex;
void *genBin(void *arg);

int main (int argc, char **argv) {
  if (argc != 2) {
    fprintf(stdout, "\nUSAGE: %s <n>\n\n", argv[0]);
    exit(EXIT_FAILURE);
  }

  int i;
  int *temp;
  num = atoi(argv[1]);
  c = num;
  r = 2;
  for (i=1; i<num; i++) {
    r=r*2;
  }

  temp = malloc(r*sizeof(int));
  pthread_mutex_init(&mutex, NULL);
  pthread_t* p;
  p = malloc(r*sizeof(pthread_t));

  for (i=0;i<r;i++) {
    temp[i] = i;  
  }

  for (i=0;i<r;i++) {
    if (pthread_create(&p[i], NULL, genBin, &temp[i])) {
      fprintf(stderr, "Error creating thread.\n");
      exit(EXIT_FAILURE);

    }
  }

  for (i=0;i<r;i++) {
    if (pthread_join(p[i], NULL)) {
      fprintf(stderr, "Error creating thread.\n");
      exit(EXIT_FAILURE);
    }
  }

  pthread_mutex_destroy(&mutex);
  free(temp);
  free(p);
  pthread_exit(0);
}

void *genBin (void *arg) {
  int x;
  int i=0;
  int *v;
  v = malloc(num*sizeof(int));
  x = *((int*)arg);

  for (i=0; i<num; i++) {
    v[i] = x%2;
    x/=2;
  }

  pthread_mutex_lock(&mutex);
  for (i=0; i<num; i++) {
    fprintf(stdout, "%d", v[i]);
  }
  fprintf(stdout, "\n");
  pthread_mutex_unlock(&mutex);

  free(v);
  pthread_exit(0);
}