2015-11-04 69 views
1

我正在实现一个信号量方法来理解同步和线程事情。我的信号量模块工作不正常(餐饮哲学家)

通过使用我的信号量,我试图解决Dining Philosophers问题。

我的计划是先制造僵局。

但我发现只有一个哲学家反复吃东西。

我通过使用其他同步问题检查了我的信号灯是否工作得很好。我认为语法有一些问题。

请让我知道是什么问题。

这是我的代码。

dinig.c(包括主要功能)

#include "sem.h" 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

static tsem_t *chopstick[5]; 
static tsem_t *updating; 

static int update_status (int i, int eating) 
{ 
    static int status[5] = { 0, }; 
    static int duplicated; 
    int idx; 
    int sum; 

    tsem_wait (updating); 

    status[i] = eating; 

    /* Check invalid state. */ 
    duplicated = 0; 
    sum = 0; 
    for (idx = 0; idx < 5; idx++) 
    { 
     sum += status[idx]; 
     if (status[idx] && status[(idx + 1) % 5]) 
    duplicated++; 
    } 

    /* Avoid printing empty table. */ 
    if (sum == 0) 
    { 
     tsem_signal (updating); 
     return 0; 
    } 

    for (idx = 0; idx < 5; idx++) 
    fprintf (stdout, "%3s  ", status[idx] ? "EAT" : "..."); 

    /* Stop on invalid state. */ 
    if (sum > 2 || duplicated > 0) 
    { 
     fprintf (stdout, "invalid %d (duplicated:%d)!\n", sum, duplicated); 
     exit (1); 
    } 
    else 
    fprintf (stdout, "\n"); 

    tsem_signal (updating); 

    return 0; 
} 

void *thread_func (void *arg) 
{ 
    int i = (int) (long) arg; 
    int k = (i + 1) % 5; 

    do 
    { 
     tsem_wait (chopstick[i]); 
     tsem_wait (chopstick[k]); 
     update_status (i, 1); 
     update_status (i, 0); 
     tsem_signal (chopstick[i]); 
     tsem_signal (chopstick[k]); 
    } 
    while (1); 

    return NULL; 
} 

int main (int argc, 
     char **argv) 
{ 
    int i; 

    for (i = 0; i < 5; i++) 
    chopstick[i] = tsem_new (1); 
    updating = tsem_new (1); 

    for (i = 0; i < 5; i++) 
    { 
     pthread_t tid; 

     pthread_create (&tid, NULL, thread_func, (void *) (long) i); 
    } 

    /* endless thinking and eating... */ 
    while (1) 
    usleep (10000000); 

    return 0; 
} 

sem.c(包括信号量的方法)

#include "sem.h" 
. 

sem.h中(标题为sem.c)

#ifndef __SEM_H__ 
#define __SEM_H__ 

#include <pthread.h> 

typedef struct test_semaphore tsem_t; 

tsem_t *tsem_new  (int  value); 
void tsem_free  (tsem_t *sem); 
void tsem_wait  (tsem_t *sem); 
int  tsem_try_wait (tsem_t *sem); 
void tsem_signal (tsem_t *sem); 

#endif /* __SEM_H__ */ 

编译命令

gcc sem.c dining.c -pthread -o dining 

enter image description here

回答

2

的一个问题是,在tsem_wait()你有一个锁之外下面的代码序列:

while(sem->count <= 0) 
    continue; 

有没有保证,该方案将实际重新阅读sem->count - 编译器可以自由生成类似以下内容的机器代码:

int temp = sem->count; 
while(temp <= 0) 
    continue; 

事实上,这可能会发生在一个优化的版本。

试着改变你的忙等循环到这样的事情所以在占用锁计数检查:

void tsem_wait (tsem_t *sem) 
{ 
    pthread_mutex_lock(&(sem->mutexLock)); 

    while (sem->count <= 0) { 
     pthread_mutex_unlock(&(sem->mutexLock)); 
     usleep(1); 
     pthread_mutex_lock(&(sem->mutexLock)); 
    } 

    // sem->mutexLock is still held here... 

    sem->count--; 
    pthread_mutex_unlock(&(sem->mutexLock)); 
} 

严格地说,你应该做的tsem_try_wait()类似的东西(这你不用还) 。

请注意,您可能需要考虑使用pthread_cond_t以使等待柜台更改效率更高。

最后,在thread_func()中用'get'筷子的代码在每个哲学家同时获得'左'筷子并最终永远等待以获得'正确'筷子(chopstick[k]),因为所有的筷子都在哲学家的左手。

+0

谢谢你体贴的回答。这对我很有帮助。但是我还不能在餐饮哲学家问题上造成僵局。正如你所说,我写了代码来制造僵局。你可以让我知道dining.c中有什么问题吗? –

+0

当我在上面进行更改时,我能够发生死锁(或者至少程序已停止 - 我认为这是一个死锁)。改变'thread_func()'中获取筷子的方式解决了这个问题。在进食和吃完食物后加上一点点时间(用'usleep(1)'调用)使输出更有趣一些。 –

+0

非常感谢。有用! –