2015-11-04 83 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

非常感謝。有用! –