如何使用 pthreads 屏障?

6

你好,很抱歉发布了一大堆代码,但我对C语言非常陌生。基本上我正在为大学作业而做一些事情,并且我必须实现一个“pthread_barrier”,现在我理解屏障的概念(至少我认为我理解了),但我不确定应该把它放在哪里。作业规定如下:

“使用pthread_barrier_init和pthread_barrier_wait确保所有生成者/消费者线程同时开始生成/消费。”

顺便说一下,这是作业的额外学分部分。

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

#define SIXTY_SECONDS 60000000
#define ONE_SECOND 1000000
#define RANGE 10
#define PERIOD 2

typedef struct {
  int *carpark;
  int capacity;
  int occupied;
  int nextin;
  int nextout;
  int cars_in;
  int cars_out;
  pthread_mutex_t lock;
  pthread_cond_t space;
  pthread_cond_t car;
  pthread_barrier_t bar;
} cp_t;

/* Our producer threads will each execute this function */
static void *
producer(void *cp_in)
{    
  cp_t *cp;
  unsigned int seed;
  /* Convert what was passed in to a pointer to a bounded buffer */
  cp = (cp_t *)cp_in;

    /* Loop */
    while (1) {
    /* Sleep for up to 1s */
    usleep(rand_r(&seed) % ONE_SECOND);
    /* Acquire the lock */
    pthread_mutex_lock(&cp->lock);
    /* While full wait until there is room available */
    while (cp->occupied == cp->capacity) {
      pthread_cond_wait(&cp->car, &cp->lock);
    }
    /* Insert an item */
    cp->carpark[cp->nextin] = rand_r(&seed) % RANGE;
    /* Increment counters */
    cp->occupied++;
    cp->nextin++;
    cp->nextin %= cp->capacity;
    cp->cars_in++;
    /* Someone may be waiting on data to become available */
    pthread_cond_signal(&cp->space);
    /* Release the lock */
    pthread_mutex_unlock(&cp->lock);
  }

  return ((void *)NULL);
}

/* Our consumer threads will each execute this function */
static void *
consumer(void *cp_in)
{

  cp_t *cp;
  unsigned int seed;
  /* Convert what was passed in to a pointer to a bounded buffer */
  cp = (cp_t *)cp_in;

  while (1) {
    /* Sleep for up to 1s */
    usleep(rand_r(&seed) % ONE_SECOND);
    /* Acquire the lock */
    pthread_mutex_lock(&cp->lock);
    /* While empty wait until there is data available */

    while (cp->occupied == 0) {
      pthread_cond_wait(&cp->space, &cp->lock);
    }

    /* Increment counters */
    cp->occupied--;
    cp->nextout++;
    cp->nextout %= cp->capacity;
    cp->cars_out++;
    /* Someone may be waiting on room to become available */
    pthread_cond_signal(&cp->car);
    /* Release the lock */
    pthread_mutex_unlock(&cp->lock);
  }

  return ((void *)NULL);
}

/* Our monitor thread will each execute this function */
static void *
monitor(void *cp_in)
{

  cp_t *cp;
  /* Convert what was passed in to a pointer to a bounded buffer */
  cp = (cp_t *)cp_in;

  while (1) {
    /* Pause */
    sleep(PERIOD);
    /* Acquire the lock */
    pthread_mutex_lock(&cp->lock);
    printf("Delta: %d\n", cp->cars_in - cp->cars_out);
    /* Release the lock */
    pthread_mutex_unlock(&cp->lock);
  }

  return ((void *)NULL);
}

/* Initialisation */
static int
init(cp_t *cp, int capacity)
{

  /* Set up the bounded buffer internals */
  cp->occupied = cp->nextin = cp->nextout = cp->cars_in = cp->cars_out = 0;
  cp->capacity = capacity;
  /* Initialise our data structure */
  cp->carpark = (int *)malloc(cp->capacity * sizeof (*cp->carpark));
  /* Check malloc succeeded */

  if (cp->carpark == NULL) {
    perror("malloc()");
    exit(EXIT_FAILURE);
  }

  /* Initialise lock and condition variables */
  pthread_mutex_init(&cp->lock, NULL);
  pthread_cond_init(&cp->space, NULL);
  pthread_cond_init(&cp->car, NULL);  
  /* Seed random number generator */
  srand((unsigned int)getpid());

  return (0);
}

int
main(int argc, char *argv[])
{

  pthread_t p, c, m;
  cp_t cp;
  /* Check usage */

  if (argc != 2) {
    printf("Usage: %s buffer_size\n", argv[0]);
    exit(EXIT_FAILURE);
  }

  /* Initialise */
  init(&cp, atoi(argv[1]));
  /* Create our threads */
  pthread_create(&p, NULL, producer, (void *)&cp);
  pthread_create(&p, NULL, producer, (void *)&cp);
  pthread_create(&c, NULL, consumer, (void *)&cp);
  pthread_create(&c, NULL, consumer, (void *)&cp);
  pthread_create(&m, NULL, monitor, (void *)&cp);
  /* Wait for our threads */
  pthread_join(p, NULL);
  pthread_join(p, NULL);
  pthread_join(c, NULL);
  pthread_join(c, NULL);
  pthread_join(m, NULL);

  return (0);
}

10
我不明白任何人如何在没有直接给出答案的情况下帮助你。因此,你为什么应该因此获得额外学分?你能告诉我们你的想法吗?你尝试过什么? - Lasse V. Karlsen
我稍微修改了标题,如果您不同意,请随时回滚。 - cnicutar
抱歉回复晚了,我有一场考试要准备,所以把这个放在了后面。 - Ian
1个回答

8

我可能可以给你完整的答案,但我害怕Lasse V. Karlsen。所以我会给你一些提示。

  • 障碍对象bar已经在您的struct cp_t中可访问
  • 像初始化互斥锁一样使用pthread_barrier_init进行初始化。 count和演员数量之间存在对应关系。
  • 生产者和消费者都需要等待才能开始生产/消费。明白了吗?

7
你应该害怕才对!咆哮声~ 在这里,我们的版主们把帖子当早餐。开玩笑的,我并不想阻止别人回答他的问题,我只是在质疑他提问的方式,他基本上是说“如果我回答这个问题,我可以得到额外的学分,但我不知道答案,你能给我吗?”更好的方式是解释他的想法、背后的推理,并要求人们拆穿他的假设或结果。但是,确实应该害怕,非常地害怕。 :) - Lasse V. Karlsen
是的,这确实帮了很多忙!我有一个关于如何使用它的想法,但当我运行代码时,如果我做得正确,它与终端输出无法区分:S。不过我现在对它有了更好的理解!我明天才有机会尝试它,但当我让它工作时,我会在帖子底部更新新代码:)谢谢大家!! - Ian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接