协调多个posix信号量

时间:2017-10-07 03:29:59

标签: c multithreading pthreads posix semaphore

跨两个信号量处理多个线程的最佳方法是什么?我正在学习C和关于信号量,所以我正在研究一种受到启发的餐饮哲学家。

两个表格(每个表格由信号量控制,每个信号量最多有4个插槽,总共8个表示板块)。一个服务器信号量,用于管理由pthreads代表的10个客户。前四个客户应该转到表A,5-8到表B,两个客户在可用时占用插槽。顾客吃完饭,回到关键区域等待另一个座位。

到目前为止,我认为已经实施的服务器信号量可以将10个客户安排在8个座位中的一个座位上。然而,我拥有它的方式,每个客户都去吃表A,然后表B然后完成,因为我只是在学习这些是如何工作的(现在看看它是有意义的。)

每个人都是自己在餐桌旁吃饭吗?或者这是同时的...我不知道。 如何检查信号量是否被阻止,传递到表A或B?

找到了另一个有帮助的thread,但没有明确的答案。

更新 从SO用户那里获得了一些有关sem_trywait的有用见解。使用oracle手册页建议,我也尝试使用sem_getvalue。我是否错误地使用了它:'将信号量的当前值指向sem指向sval指向的整数'。我将此解释为向我提供了尝试访问sempahore的当前线程数。想要使用它来让客户在完成后重新进入表中(无限次地将客户循环回到表中直到程序被杀死)。

问题是,我现在陷入僵局。我很困惑为什么人们会先坐在B座上。

我的代码(更新: - 修改吃功能;吃掉的原始代码注释掉):

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


sem_t server_sem;
int server_pshared;
int server_ret;
int server_count = 8;

sem_t tablea_sem;
int tablea_pshared;
int tablea_ret;
int tablea_count = 4;

sem_t tableb_sem;
int tableb_pshared;
int tableb_ret;
int tableb_count = 4;



//server_ret = serm_open("serverSem", O_CREAT | O_EXCL, 0644, server_count);

int customer_count = 10;
pthread_t customer[10];
//pthread_t plates[8]

int plate_count = 8;
pthread_mutex_t plates;


//void *eat(int n) {
void *eat(void *i) {

    //int n = *((int *) i);
    int n = (int)(intptr_t) i;

  //UPDATED CODE -- see console output 2
  int num_plates;

  sem_wait(&server_sem);

  if (sem_trywait(&tablea_sem) != 0)
  if (errno == EAGAIN) { //no plate at table A available
    //sem_trywait(&tableb_sem)
    sem_wait(&tableb_sem);
    pthread_mutex_lock(&plates);
    plate_count--;
    printf("Customer %d is eating at Table B\n", n);
    //printf("Plate count is %d\n", n);
    sleep(2);
    pthread_mutex_unlock(&plates);
    sem_getvalue(&tableb_sem, &num_plates);
    printf("Num plate %d", num_plates);
    sem_post(&tableb_sem);
    printf("Customer %d is finished eating at Table B\n", n);
  }
  else {
    sem_wait(&tablea_sem);
    pthread_mutex_lock(&plates);
    plate_count--;
    printf("Customer %d is eating at Table A\n", n);
    sleep(2);
    pthread_mutex_unlock(&plates);
    sem_getvalue(&tablea_sem,&num_plates);
    printf("Num plate %d", num_plates);
    sem_post(&tablea_sem);
    printf("Customer %d is finished eating at Table A\n", n);

  }

  //---> Original post code commented out
  // sem_wait(&tablea_sem);
  // pthread_mutex_lock(&plates);
  // plate_count--;
  // printf("Customer %d is eating at Table A\n", n);
  // sleep(2);
  // pthread_mutex_unlock(&plates);
  // sem_post(&tablea_sem);
  // printf("Customer %d is finished eating at Table A\n", n);
  //
  // sem_wait(&tableb_sem);
  // pthread_mutex_lock(&plates);
  // plate_count--;
  // printf("Customer %d is eating at Table B\n", n);
  // //printf("Plate count is %d\n", n);
  // sleep(2);
  // pthread_mutex_unlock(&plates);
  // sem_post(&tableb_sem);
  // printf("Customer %d is finished eating at Table B\n", n);



    return (NULL);

}

int main() {


   server_ret = sem_init(&server_sem, 1, server_count);
   tablea_ret = sem_init(&tablea_sem, 1, tablea_count);
   tableb_ret = sem_init(&tableb_sem, 1, tableb_count);

   //customer = (pthread_t[10] *)malloc(sizeof(customer));

   printf ("starting thread, semaphore is unlocked.\n");

   int i;
   int j;
   int k;


   pthread_mutex_init(&plates,NULL);



   //sem_wait(&server_sem);
   for (j=0;j<customer_count;j++) {
     pthread_create(&customer[j],NULL,(void *)eat,(void *) (intptr_t) j);
   }

   for(k=0;k<customer_count;k++) {
      pthread_join(customer[k],NULL);
      printf("Joining thread %d\n", k);
   }


   pthread_mutex_destroy(&plates);

   //sem_post(&server_sem);


   return 0;
   }

控制台输出:

niu@niu-vb:~/Documents/CSU_OS$ ./diner
starting thread, semaphore is unlocked.
Customer 6 is eating at Table A
Customer 6 is finished eating at Table A
Customer 6 is eating at Table B
Customer 6 is finished eating at Table B
Customer 8 is eating at Table A
Customer 8 is finished eating at Table A
Customer 8 is eating at Table B
Customer 8 is finished eating at Table B
Customer 7 is eating at Table A
Customer 7 is finished eating at Table A
Customer 7 is eating at Table B
Customer 7 is finished eating at Table B
Customer 9 is eating at Table A
Customer 9 is finished eating at Table A
Customer 9 is eating at Table B
Customer 9 is finished eating at Table B
Customer 5 is eating at Table A
Customer 5 is finished eating at Table A
Customer 5 is eating at Table B
Customer 5 is finished eating at Table B
Customer 4 is eating at Table A
Customer 4 is finished eating at Table A
Customer 4 is eating at Table B
Customer 4 is finished eating at Table B
Customer 3 is eating at Table A
Customer 3 is finished eating at Table A
Customer 3 is eating at Table B
Customer 3 is finished eating at Table B
Customer 2 is eating at Table A
Customer 2 is finished eating at Table A
Customer 2 is eating at Table B
Customer 2 is finished eating at Table B
Customer 1 is eating at Table A
Customer 1 is finished eating at Table A
Customer 1 is eating at Table B
Customer 1 is finished eating at Table B
Customer 0 is eating at Table A
Customer 0 is finished eating at Table A
Customer 0 is eating at Table B
Customer 0 is finished eating at Table B
Joining thread 0
Joining thread 1
Joining thread 2
Joining thread 3
Joining thread 4
Joining thread 5
Joining thread 6
Joining thread 7
Joining thread 8
Joining thread 9

控制台输出2:

Starting program: /home/niu/Documents/CSU_OS/diner 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
starting thread, semaphore is unlocked.
[New Thread 0x7ffff77f6700 (LWP 20306)]
[New Thread 0x7ffff6ff5700 (LWP 20307)]
[Thread 0x7ffff77f6700 (LWP 20306) exited]
[New Thread 0x7ffff67f4700 (LWP 20308)]
[Thread 0x7ffff6ff5700 (LWP 20307) exited]
[New Thread 0x7ffff5ff3700 (LWP 20309)]
[Thread 0x7ffff67f4700 (LWP 20308) exited]
[New Thread 0x7ffff57f2700 (LWP 20310)]
Customer 4 is eating at Table B
[Thread 0x7ffff5ff3700 (LWP 20309) exited]
[New Thread 0x7ffff4ff1700 (LWP 20311)]
[New Thread 0x7ffff47f0700 (LWP 20312)]
[New Thread 0x7ffff3fef700 (LWP 20313)]
[New Thread 0x7ffff37ee700 (LWP 20314)]
[New Thread 0x7ffff2fed700 (LWP 20315)]
Joining thread 0
Joining thread 1
Joining thread 2
Joining thread 3
Num plate 1Customer 4 is finished eating at Table B
Customer 5 is eating at Table B
Joining thread 4
[Thread 0x7ffff57f2700 (LWP 20310) exited]
Num plate 2Customer 5 is finished eating at Table B
Customer 6 is eating at Table B
Joining thread 5
[Thread 0x7ffff4ff1700 (LWP 20311) exited]
Num plate 3Customer 6 is finished eating at Table B
Joining thread 6
[Thread 0x7ffff47f0700 (LWP 20312) exited]

1 个答案:

答案 0 :(得分:0)

使用信号量来控制对可能想要的线程的资源的访问权限是很棘手的。您可以使用sem_trywait;为避免在表A和表B之间来回切换,您可以添加一个保护两个表的信号量(当然,初始计数为8)。

然后每个客户线程在循环中降低外部信号量,尝试降低A的信号量,如果失败则降低B的信号量。 (如果你不想支持A,你可以用其他顺序尝试它们。)然后它选择它和外部信号量。

请注意,这与container="body"或多或少相同,其目的在您的代码中不明确。