c-POSIX信号量和pthread问题



我正在使用POSIX库练习信号量。我试图通过一个信号量(代表服务器)传递线程(代表客户),该信号量将8个人放在两个表(每个表由信号量控制)上。我认为罪魁祸首是解锁和锁定多个信号量的顺序,但我似乎无法确定非法指令(核心转储)错误的来源。

编辑-互斥初始化的颠倒顺序和创建线程循环-在eat()的末尾添加了return NULL:

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

sem_t server_sem;
int server_pshared;
int server_ret;
int server_count = 10;
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[8];

void *eat(int n) {
sem_wait(&server_sem);
printf("Sitting down at Table An");
//unlock table a semaphore
sem_wait(&tablea_sem);
//unlock 
pthread_mutex_lock(&plates[n]);
printf("Customer %d is eatingn", n);
sleep(5);
pthread_mutex_unlock(&plates[n]);
printf("Customer %d is finished eatingn", n);
//sem_post(&server_sem);
sem_post(&tablea_sem);
printf("Sitting down at Table An");
//unlock table b semaphore
sem_wait(&tableb_sem);
//unlock 
//sem_wait(&server_sem);
pthread_mutex_lock(&plates[n]);
printf("Customer %d is eatingn", n);
sleep(5);
pthread_mutex_unlock(&plates[n]);
printf("Customer %d is finished eatingn", n);

sem_post(&tableb_sem);
sem_post(&server_sem);
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;
for(i=0;i<plate_count;i++)
pthread_mutex_init(&plates[i],NULL);
for (i=0;i<customer_count;i++)
pthread_create(&customer[i],NULL,(void *)eat,(void *)i);

//for(i=0;i<plate_count;i++)
//   pthread_mutex_init(&plates[i],NULL);

for(i=0;i<customer_count;i++)
pthread_join(customer[i],NULL);
for(i=0;i<plate_count;i++)
pthread_mutex_destroy(&plates[i]);
return 0;
}

更新

我已经接受了一个答案,因为它让我对最初的问题有了很好的了解。可能仍然是,而且只是我对这个话题缺乏理解(轻描淡写)。一些研究(手册页和这个帖子)让我修复了SO回复者提到的错误,并继续尽我所能进行调整。

现在,下面更新的代码已尝试处理已接受的答案。但是,我得到了相同的输出。。。我还没有抓住要点吗?

#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 = 10;
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[8];

//void *eat(int n) {
void *eat(void *i) {
//int n = *((int *) i);
int n = (int)(intptr_t) i;
//printf("Customer %d is eating", m);
sem_wait(&server_sem);

int j;
for (j = 0; j<4; j++) {
sem_wait(&tablea_sem);
pthread_mutex_lock(&plates[j]);
printf("Customer %d is eatingn", n);
printf("Plate %d is eatenn", j);
sleep(5);
pthread_mutex_unlock(&plates[j]);
printf("Customer %d is finished eatingn", n);
sem_post(&tablea_sem);
}
for (j = 4; j<8; j++) {
sem_wait(&tableb_sem);
pthread_mutex_lock(&plates[j]);
printf("Customer %d is eatingn", n);
printf("Plate %d is eatenn", j);
sleep(5);
pthread_mutex_unlock(&plates[j]);
printf("Customer %d is finished eatingn", n);
sem_post(&tableb_sem);
}
j--;

sem_post(&server_sem);

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;


for(i=0;i<plate_count;i++) {
pthread_mutex_init(&plates[i],NULL);
printf("Creating mutex for plate %dn", i);
}
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 %dn", k);
}

for(i=0;i<plate_count;i++) {
pthread_mutex_destroy(&plates[i]);
}
sem_post(&server_sem);

return 0;
}

gdb调试输出(无断点):

niu@niu-vb:~/Documents/CSU_OS$ gcc -pthread -o -g  diner diner4.c
diner: In function `_fini':
(.fini+0x0): multiple definition of `_fini'
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crti.o(.debug_info): relocation 0 has invalid symbol index 7
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crti.o(.debug_info): relocation 1 has invalid symbol index 8
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crti.o(.debug_info): relocation 2 has invalid symbol index 9
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crti.o(.debug_ranges): relocation 0 has invalid symbol index 4
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crti.o(.debug_ranges): relocation 1 has invalid symbol index 4
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crti.o(.debug_ranges): relocation 2 has invalid symbol index 5
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crti.o(.debug_ranges): relocation 3 has invalid symbol index 5
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crti.o:(.fini+0x0): first defined here
diner: In function `data_start':
(.data+0x0): multiple definition of `__data_start'
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 0 has invalid symbol index 11
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 1 has invalid symbol index 12
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 2 has invalid symbol index 2
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 3 has invalid symbol index 2
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 4 has invalid symbol index 11
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 5 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 6 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 7 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 8 has invalid symbol index 12
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 9 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 10 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 11 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 12 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 13 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 14 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 15 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 16 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 17 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 18 has invalid symbol index 13
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 19 has invalid symbol index 21
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_line): relocation 0 has invalid symbol index 2
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o:(.data+0x0): first defined here
diner: In function `data_start':
(.data+0x8): multiple definition of `__dso_handle'
/usr/lib/gcc/x86_64-linux-gnu/4.8/crtbegin.o:(.data+0x0): first defined here
diner:(.rodata+0x0): multiple definition of `_IO_stdin_used'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o:(.rodata.cst4+0x0): first defined here
diner: In function `_start':
(.text+0x0): multiple definition of `_start'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o:/build/eglibc-oGUzwX/eglibc-2.19/csu/../sysdeps/x86_64/start.S:118: first defined here
diner: In function `_init':
(.init+0x0): multiple definition of `_init'
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crti.o(.debug_line): relocation 0 has invalid symbol index 4
/usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crti.o(.debug_line): relocation 1 has invalid symbol index 5
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crti.o:/build/eglibc-oGUzwX/eglibc-2.19/csu/../sysdeps/x86_64/crti.S:64: first defined here
/tmp/cc8RaCJg.o:(.data+0x0): multiple definition of `server_count'
diner:(.data+0x10): first defined here
/tmp/cc8RaCJg.o:(.data+0x4): multiple definition of `tablea_count'
diner:(.data+0x14): first defined here
/tmp/cc8RaCJg.o:(.data+0x8): multiple definition of `tableb_count'
diner:(.data+0x18): first defined here
/tmp/cc8RaCJg.o:(.data+0xc): multiple definition of `customer_count'
diner:(.data+0x1c): first defined here
/tmp/cc8RaCJg.o:(.data+0x10): multiple definition of `plate_count'
diner:(.data+0x20): first defined here
/tmp/cc8RaCJg.o: In function `eat':
diner4.c:(.text+0x0): multiple definition of `eat'
diner:(.text+0xed): first defined here
/tmp/cc8RaCJg.o: In function `main':
diner4.c:(.text+0x184): multiple definition of `main'
diner:(.text+0x271): first defined here
/usr/lib/gcc/x86_64-linux-gnu/4.8/crtend.o:(.tm_clone_table+0x0): multiple definition of `__TMC_END__'
diner:(.data+0x28): first defined here
/usr/bin/ld: error in diner(.eh_frame); no .eh_frame_hdr table will be created.
collect2: error: ld returned 1 exit status
niu@niu-vb:~/Documents/CSU_OS$ gdb diner
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.3) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from diner...(no debugging symbols found)...done.
(gdb) run
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.
Creating mutex for plate 0
Creating mutex for plate 1
Creating mutex for plate 2
Creating mutex for plate 3
Creating mutex for plate 4
Creating mutex for plate 5
Creating mutex for plate 6
Creating mutex for plate 7
[New Thread 0x7ffff77f6700 (LWP 18606)]
Customer 0 is eating
[New Thread 0x7ffff6ff5700 (LWP 18607)]
Customer 1 is eating
[New Thread 0x7ffff67f4700 (LWP 18608)]
Customer 2 is eating
[New Thread 0x7ffff5ff3700 (LWP 18609)]
Customer 3 is eating
[New Thread 0x7ffff57f2700 (LWP 18610)]
[New Thread 0x7ffff4ff1700 (LWP 18611)]
[New Thread 0x7ffff47f0700 (LWP 18612)]
[New Thread 0x7ffff3fef700 (LWP 18613)]
[New Thread 0x7ffff37ee700 (LWP 18614)]
[New Thread 0x7ffff2fed700 (LWP 18615)]
Customer 0 is finished eating
Customer 1 is finished eating
Customer 2 is finished eating
Customer 3 is finished eating

畸形/未定义行为

正如我在评论中所描述的,您的程序中至少有两个未定义行为的来源:

  1. 您试图使用eat()作为线程启动函数,但它的类型不正确。线程启动函数必须接受void *类型的单个参数并返回void *,但eat()的参数是int类型的。由于参数类型不匹配,您对pthread_create()的调用具有未定义的行为。在某种程度上,pthread_create()可以被解释为调用指向函数,该调用也将具有自己未定义的行为。

  2. 您调度了十个客户线程,每个线程都试图锁定不同的板互斥,但只有八个板互斥可用。因此,如果你真的假设eat()接收到你想要它执行的参数值,你就必须超出板互斥体数组的边界。即使你想象溢出会导致操作可访问内存(它是否真的这样做是未定义的),内存肯定还没有通过pthread_mutex_init()初始化用作互斥体。

其中一个或两个可能对您的segfault负责。

奇怪的行为

您创建并使用了一堆不需要的同步对象。eat()函数的整个主体由信号量server_sem保护,使用该信号量的方式确保执行该函数的线程永远不会超过一个。因此,互斥和其他信号量内部的所有使用都是无意义的——这些其他同步对象永远不会有任何争用。

在编写eat()时,让每个客户线程依次锁定每个表信号量,并在每个信号量的保护下锁定一个板互斥。就你试图模仿的东西而言,每个顾客吃两次,每桌一次,但都是从同一个盘子里吃的。

每个客户线程使用不同的板(或尝试这样做),因此没有板的竞争。在没有争用的情况下,不需要互斥来保护板访问,即使服务器信号量不是防止争用。

总的来说,我不清楚你试图建立什么样的互动模型。如果你也不清楚,那么这可能是你遇到一些困难的原因。我倾向于猜测,也许您希望另一个线程代表一个服务器,它将与客户线程合作,将它们分配给可用的席位。即便如此,我也不确定是否看到了板互斥的用途。

这里的整个前提对我来说似乎有点奇怪,因为我从未看到任何会导致任何线程阻塞的争用。尽管如此,我确实看到了一个会导致程序崩溃的特定缺陷。

线程中有8个"plates"(互斥对象)和10个"customers",即值"n"。

pthread_mutex_lock(&plates[n]);

将在n=7时正常工作,然后在n=8时崩溃,因为它指向无效内存。

此外,pthread入口函数的正确原型是void *function(void* arg)(而不是int)。如果需要的话,您必须将该值作为void*传递,然后在本地将其强制转换回int,但请注意,这也可能会产生关于截断的编译器警告,因为在许多平台上,int小于void*

最新更新