2015-06-26 54 views
1

我正在用pthreads建模火車站。每個火車都有自己的線程和自己的條件變量,用來監視對主線路的訪問。列車信息被從文件中讀取並且是以下格式:pthread同步建模爲火車站

(方向):(加載時間):(渡時間)

只有一個列車可在一個時間在主軌道上。火車不能在主軌道上,除非他們被裝載並準備就緒。

有一個單獨的調度員線程負責協調所有列車之間的主要軌道訪問。調度員線程還根據各種規則來決定哪些列車可以進入,例如列車正在進入哪個方向。現在,如果我可以讓列車按照他們準備好的順序到達主軌道,我會很高興。

這是到目前爲止我的代碼:

#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 
#include <string.h> 
#include <readline/readline.h> 
#include <unistd.h> 

struct Train{ 
    pthread_t thread; 
    pthread_cond_t granted; 

    int train_number; 
    int loading_time; 
    int crossing_time; 

    int priority; 
    char direction; 
    char state; 

}*newTrain; 

struct Train *trains[3]; 

pthread_mutex_t track  = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t dispatcher = PTHREAD_COND_INITIALIZER; 

char *loading = "L"; 
char *ready = "R"; 
char *granted_t = "T"; 
char *gone = "G"; 
char *acknowledged_gone = "X"; 

void *dispatcher_function(void *train_count) { 
    int count = *((int *) train_count); 
    int trains_remaining = count; 

    /* Check for ready trains until all trains have left the station */ 
    while (trains_remaining > 0) { 
     pthread_mutex_lock(&track); 

     int t_granted = 0; 
     int next = -1; 

     for(int i = 0; i < count; i++){ 
      if (strcmp(&trains[i]->state, "T") == 0) 
       t_granted = 1; 
      if (strcmp(&trains[i]->state, "R") == 0) 
       next = i; 
      if (strcmp(&trains[i]->state, "G") == 0){ 
       trains_remaining--; 
       trains[i]->state = *acknowledged_gone; 
      } 
     } 

     /* Train was granted access to station wait for it to leave */ 
     if (t_granted) { 
      pthread_cond_wait(&dispatcher, &track); 
     } 

     /* No trains in station. Wait for train */ 
     if (next == -1) { 
      pthread_cond_wait(&dispatcher, &track); 
     } 

     /* Train ready in station grant next train track permission*/ 
     else{ 
      trains[next] -> state = *granted_t; 
      pthread_cond_signal(&(trains[next] -> granted)); 
     } 
     pthread_mutex_unlock(&track); 
    } 
    pthread_exit(0); 
} 

void *train_function(void* train) { 
    struct Train *self = (struct Train*)train; 

    /* Each train has its own cond var */ 
    pthread_cond_init(&self->granted, NULL); 

    /* Load train */ 
    usleep(self -> loading_time); 

    /* Lock track */ 
    pthread_mutex_lock(&track); 

    /* Train ready */ 
    self -> state = *ready; 
    printf("Train %d is ready to go %c\n", self -> train_number, self -> direction); 

    /* Signal dispatcher */ 
    pthread_cond_signal(&dispatcher); 

    while(strcmp(&self->state, "T") != 0) 
     pthread_cond_wait(&(self->granted), &track); 

    /* Use the track */ 
    printf("Train %d is ON the main track going %c\n", self -> train_number, self -> direction); 
    usleep(self -> crossing_time); 
    self -> state = *gone; 
    printf("Train %d is OFF the main track after going %c\n", self -> train_number, self -> direction); 

    pthread_cond_signal(&dispatcher); 
    pthread_mutex_unlock(&track); 

    pthread_exit(0); 
} 

int main() { 

    FILE *ptr_file; 
    char buff[10]; 
    int train_count = 0; 
    char *train; 
    char line[15]; 
    pthread_t train_threads[3]; 
    pthread_t dispatcher_thread; 

    ptr_file = fopen("./trains.txt", "r"); 
    if (!ptr_file) 
    { 
     perror("fopen for trains.txt failed"); 
     exit(EXIT_FAILURE); 
    } 

    /* Create train for each line of file */ 
    while (fgets(buff,10, ptr_file)!=NULL) { 
     train = (char*)malloc(10 * sizeof(char)); 

     /* Build train string */ 
     sprintf(line, "%d:", train_count); 
     strcat(line, buff); 
     strcpy(train, line); 

     /* Parse train information */ 
     int line_number = atoi(strtok(train, ":,")); 
     char *direction = strtok(NULL,":,"); 
     int loading_time = atoi(strtok(NULL, ":,")); 
     int crossing_time = atoi(strtok(NULL, ":,")); 

     /* Create trains */ 
     newTrain = (struct Train *) malloc(sizeof(struct Train)); 
     newTrain -> train_number = line_number; 
     newTrain -> crossing_time = crossing_time; 
     newTrain -> loading_time = loading_time; 
     newTrain -> direction = *direction; 
     newTrain -> state = *loading; 

     if(pthread_create(&train_threads[train_count], NULL, &train_function, (void *) newTrain)) 
     { 
      perror("pthread create failed"); 
      exit(EXIT_FAILURE); 
     } 

     trains[line_number] = newTrain; 
     train_count++; 
    } 
    fclose(ptr_file); 

    /* Create dispatcher */ 
    if(pthread_create(&dispatcher_thread, NULL, &dispatcher_function, (void *) &train_count)) 
    { 
     perror("pthread create failed"); 
     exit(EXIT_FAILURE); 
    } 

    /* Wait for dispatcher to finish */ 
    pthread_join(dispatcher_thread, NULL); 
    printf("all done"); 

    free(train); 
    for (int i = 0; i < train_count; i++) { 
     free(trains[i]); 
    } 
    exit(EXIT_SUCCESS); 
} 

這裏是trains.txt輸入文件:

e:10,6 
W:5,7 
E:3,10 

這是輸出我得到當我運行它:

Train 0 is ready to go e 
Train 0 is ON the main track going e 
Train 0 is OFF the main track after going e 
Train 2 is ready to go E 
Train 1 is ready to go W 
Train 2 is ON the main track going E 
Train 2 is OFF the main track after going E 
Train 1 is ON the main track going W 
Train 1 is OFF the main track after going W 

所有火車離開車站後,該程序將掛起。如此接近我一定會錯過一些東西。

+0

我管理的兩排更僵局 –

+0

之前,我看不出你初始化'granted'條件變量。 – user3386109

回答

1

您有需要加以糾正你的程序可以思索前幾個錯誤:

trains.state是單char對象 - 它不是一個字符串,因爲它不一定後跟一個空終止符。這意味着,就像你在幾個地方你可以不是它的地址傳遞給strcmp() - 而不是這樣的:一個字符常量

if (trains[i]->state == 'T') 

(注意單引號代替:

if (strcmp(&trains[i]->state, "T") == 0) 

使用一個字符串常量)。

你不能free(train)train_function()結束,因爲調度員保持運行和需要訪問所有火車結構。相反,在調度員退出後,將其全部釋放到main()中。

列車條件變量granted並未初始化。您不能複製周圍pthread_cond_t變量 - 改用pthread_cond_init

void *train_function(void* train) 
{ 
    struct Train *self = (struct Train*)train; 

    /* Each train has its own cond var */ 
    pthread_cond_init(&self->granted, NULL); 

train_function()修改開始self->state無持有鎖定,這意味着它可以與調度員讀同一對象比賽。你需要保持周圍的修改鎖:

/* Load train */ 
pthread_mutex_lock(&track); 
self -> state = *loading; 
pthread_mutex_unlock(&track); 
usleep(self -> loading_time); 

/* Lock track */ 
pthread_mutex_lock(&track); 

/* Train ready */ 
self -> state = *ready; 
printf("Train %d is ready to go %c\n", self -> train_number, self -> direction); 

(您可以通過初始化state避免第一鎖定爲「加載」的所有列車在main(),其他線程之前開始)。


此外,您不能假設你正在等待條件爲真,只是因爲pthread_cond_wait()已經甦醒。即使沒有發信號,也允許返回pthread_cond_wait();它只返回意味着它可能可能已被髮信號。這意味着,例如在train_function,您使用while代替if需要在pthread_cond_wait()周圍循環:

while (self->state != 'T') 
    pthread_cond_wait(&self->granted, &track); 

你需要做的調度員,你會發現有一列火車上的情況類似軌道。

這實際上是你的問題的心臟 - 當你得到在這一點上喚醒:

if (t_granted) { 
    pthread_cond_wait(&dispatcher, &track); 
    trains_remaining--; 
} 

承擔這是因爲你在鐵軌上看到火車已經完成。但事實並非如此 - 你可能已經通過下一個列車整理加載信號。這意味着你會繞着循環再次看到軌道上的同一列火車,並且太多地減少trains_remaining

所以,當你在軌道上看到一列火車時,你不能僅僅調整trains_remaining,因爲如果它很快就會「消失」,你可能會看到同一列火車兩次 - 或根本沒有。

相反,你應該第一次減少trains_remaining,你看到一個給定的列車處於「消失」狀態。調度員設置火車後,它已經看到了,這是「水漲船高」你可以通過添加一個新的國家實現這一目標,是這樣的:

for (int i = 0; i < count; i++) { 
     if (trains[i]->state == 'T') 
      t_granted = 1; 
     if (trains[i]->state == 'R') 
      next = i; 
     if (trains[i]->state == 'G') { 
      trains_remaining--; 
      trains[i]->state = 'X'; /* acknowledged gone */ 
     } 
    } 
+0

在調試器中,第一個信號是'pthread_cond_signal(&(trains [next] - > granted));'所以它後面跟着'pthread_cond_wait(&dispatcher,&track);'並且保持那樣,'next'是-1最後,不是在開始。鎖定調度程序線程等待信號。 –

+0

我已經對我的代碼進行了所有建議的更改,除了在strcmp中訪問火車狀態外。當我嘗試使用你建議的語法進行編譯時,我得到了這樣的結果:錯誤:請求成員'狀態',而不是結構或聯盟 – CaddyShack

+0

通過更加嚴格的測試,我的快速修復不夠充分,連續三次或四次運行後,在執行中。需要更強大的解決方案。 –