跨两个信号量处理多个线程的最佳方法是什么?我正在学习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]
答案 0 :(得分:0)
使用信号量来控制对可能想要的线程的资源的访问权限是很棘手的。您可以使用sem_trywait
;为避免在表A和表B之间来回切换,您可以添加一个保护两个表的信号量(当然,初始计数为8)。
然后每个客户线程在循环中降低外部信号量,尝试降低A的信号量,如果失败则降低B的信号量。 (如果你不想支持A,你可以用其他顺序尝试它们。)然后它选择它和外部信号量。
请注意,这与container="body"
或多或少相同,其目的在您的代码中不明确。