2013-03-25 53 views
0

我目前正在玩弄信號量並試圖理解它們。我試圖按照教程要求我編輯示例代碼,讓程序運行兩個輪流將歌詞輸出到歌曲('There's a hole in the bucket')的進程。如何在使用信號量的進程之間執行操作順序?

我的問題是,當我在程序中添加歌曲的更多行時,進程不會交替進行,但只有兩行時它們才能正常工作。

一個過程處理麗莎的另一部分,另一個亨利的一部分。這是我的代碼:

#include <sys/ipc.h> 
#include <sys/sem.h> 
#include <stdio.h> 
#include <stdlib.h> 

#define KEY 87654 //Unique semaphore key 

int main() 
{ 
    int id; /* Number by which the semaphore is known within a program */ 

    union semun { 
    int val; 
    struct semid_ds *buf; 
    ushort * array; 
    } argument; 

    argument.val = 1; 

    /* Create the semaphore with external key KEY if it doesn't already 
    exists. Give permissions to the world. */ 
    id = semget(KEY, 1, 0666 | IPC_CREAT); 

    /* Always check system returns. */  
    if(id < 0) { 
     fprintf(stderr, "Unable to obtain semaphore.\n"); 
     exit(0); 
    } 

    /* What we actually get is an array of semaphores. The second 
    argument to semget() was the array dimension - in our case 
    1. */ 

    /* Set the value of the number 0 semaphore in semaphore array 
    # id to the value 0. */  
    if(semctl(id, 0, SETVAL, argument) < 0) { 
     fprintf(stderr, "Cannot set semaphore value.\n"); 
    } else { 
     fprintf(stderr, "Semaphore %d initialized.\n", KEY); 
    } 

    int pid=fork(); 

    if(pid) { 
    struct sembuf operations[1]; 
    int retval; /* Return value from semop() */ 

    /* Get the index for the semaphore with external name KEY. */ 
    id = semget(KEY, 1, 0666); 

    if(id < 0){ 
     /* Semaphore does not exist. */ 

     fprintf(stderr, "Program sema cannot find semaphore, exiting.\n"); 
     exit(0); 
    } 
    operations[0].sem_num = 0; 
    /* Which operation? Subtract 1 from semaphore value : */ 
    operations[0].sem_op = -1; 
    /* Set the flag so we will wait : */ 
    operations[0].sem_flg = 0; 

    while(1){ 
     //Process 1 

     //wait 
     operations[0].sem_op = -1; 
     retval = semop(id, operations, 1); 

     //critical section 
     printf("Then mend it, dear Henry, dear Henry, dear Henry, \n"); 
     printf("Then mend it, dear Henry, dear Henry, mend it. \n"); 

     fflush(stdout); 
     int stime=2+(rand()/(float)(RAND_MAX))*4; 
     printf("Sleeping for %d secs\n",stime); 
     sleep(stime); 

     printf("With a straw, dear Henry, dear Henry, dear Henry, \n"); 
     printf("With a straw, dear Henry, dear Henry, with a straw. \n"); 

     fflush(stdout); 

     int stim1e=2+(rand()/(float)(RAND_MAX))*4; 
     printf("Sleeping for %d secs\n",stim1e); 
     sleep(stim1e); 

     printf("Then cut it, dear Henry, dear Henry, dear Henry, \n"); 
     printf("Then cut it, dear Henry, dear Henry, cut it. \n"); 

     fflush(stdout); 
     int stim2e=2+(rand()/(float)(RAND_MAX))*4; 
     printf("Sleeping for %d secs\n",stim2e); 
     sleep(stim2e); 

     printf("With a knife, dear Henry, dear Henry, dear Henry, \n"); 
     printf("With a knife, dear Henry, dear Henry, with a knife. \n"); 
     fflush(stdout); 

     int stim3e=2+(rand()/(float)(RAND_MAX))*4; 
     printf("Sleeping for %d secs\n",stim3e); 
     sleep(stim3e); 

     printf("Then sharpen it, dear Henry, dear Henry, dear Henry \n"); 
     printf("Then sharpen it, dear Henry, dear Henry, sharpen it. \n"); 

     fflush(stdout); 
     int stim4e=2+(rand()/(float)(RAND_MAX))*4; 
     printf("Sleeping for %d secs\n",stim4e); 
     sleep(stim4e); 

     printf("On a stone, dear Henry, dear Henry, dear Henry, \n"); 
     printf("On a stone, dear Henry, dear Henry, a stone. \n"); 

     fflush(stdout); 
     int stim5e=2+(rand()/(float)(RAND_MAX))*4; 
     printf("Sleeping for %d secs\n",stim5e); 
     sleep(stim5e); 

     printf("Well wet it, dear Henry, dear Henry, dear Henry, \n"); 
     printf("Well wet it, dear Henry, dear Henry, wet it. \n"); 

     fflush(stdout); 
     int stim6e=2+(rand()/(float)(RAND_MAX))*4; 
     printf("Sleeping for %d secs\n",stim6e); 
     sleep(stim6e); 

     printf("try water, dear Henry, dear Henry, dear Henry, \n"); 
     printf("try water, dear Henry, dear Henry, water. \n"); 

     fflush(stdout); 
     int stim7e=2+(rand()/(float)(RAND_MAX))*4; 
     printf("Sleeping for %d secs\n",stim7e); 
     sleep(stim7e); 

     printf("In a bucket, dear Henry, dear Henry, dear Henry, \n"); 
     printf("In a bucket, dear Henry, dear Henry, a bucket. \n"); 

     fflush(stdout); 
     int stim8e=2+(rand()/(float)(RAND_MAX))*4; 
     printf("Sleeping for %d secs\n",stim8e); 
     sleep(stim8e); 

     printf("Use your head, then! dear Henry, dear Henry, dear Henry, \n"); 
     printf("Use your head, then! dear Henry, dear Henry, use your head! \n"); 

     fflush(stdout); 

     operations[0].sem_op = 1; 
     //signal 
     retval = semop(id, operations, 1); 

    } 
    }else{ 
    //Process 2 
    struct sembuf operations[1]; 
    int retval; /* Return value from semop() */ 
    /* Get the index for the semaphore with external name KEY. */ 
    id = semget(KEY, 1, 0666); 
    if(id < 0){ 
     /* Semaphore does not exist. */ 

     fprintf(stderr, "Program sema cannot find semaphore, exiting.\n"); 
     exit(0); 
    } 
    operations[0].sem_num = 0; 
    /* Which operation? Subtract 1 from semaphore value : */ 
    operations[0].sem_op = -1; 
    /* Set the flag so we will wait : */ 
    operations[0].sem_flg = 0; 

    while(1){ 



     //wait 
     operations[0].sem_op = -1; 
     retval = semop(id, operations, 1); 

     //critical section 

     printf("There's a hole in the bucket, dear Liza, dear Liza, \n"); 
     printf("There's a hole in the bucket, dear Liza, a hole. \n"); 

     fflush(stdout); 
     int stim9e=2+(rand()/(float)(RAND_MAX))*4; 
     printf("Sleeping for %d secs\n",stim9e); 
     sleep(stim9e); 

     printf("With what shall I mend it, dear Liza, dear Liza? \n"); 
     printf("With what shall I mend it, dear Liza, with what? \n"); 
     fflush(stdout); 

     int stim0e=2+(rand()/(float)(RAND_MAX))*4; 
     printf("Sleeping for %d secs\n",stim0e); 
     sleep(stim0e); 

     printf("The straw is too long, dear Liza, dear Liza, \n"); 
     printf("The straw is too long, dear Liza, too long, \n"); 

     fflush(stdout); 
     int stimae=2+(rand()/(float)(RAND_MAX))*4; 
     printf("Sleeping for %d secs\n",stimae); 
     sleep(stimae); 

     printf("The knife is too dull, dear Liza, dear Liza, \n"); 
     printf("The knife is too dull, dear Liza, too dull. \n"); 

     fflush(stdout); 
     int stimse=2+(rand()/(float)(RAND_MAX))*4; 
     printf("Sleeping for %d secs\n",stimse); 
     sleep(stimse); 

     printf("On what shall I sharpen it, dear Liza, dear Liza? \n"); 
     printf("On what shall I sharpen it, dear Liza, on what? \n"); 

     fflush(stdout); 
     int stimde=2+(rand()/(float)(RAND_MAX))*4; 
     printf("Sleeping for %d secs\n",stimde); 
     sleep(stimde); 

     printf("The stone is too dry, dear Liza, dear Liza, \n"); 
     printf("The stone is too dry, dear Liza, too dry. \n"); 

     fflush(stdout); 
     int stimwe=2+(rand()/(float)(RAND_MAX))*4; 
     printf("Sleeping for %d secs\n",stimwe); 
     sleep(stimwe); 

     printf("With what shall I wet it, dear Liza, dear Liza? \n"); 
     printf("With what shall I wet it, dear Liza, with what? \n"); 

     fflush(stdout); 
     int stimqe=2+(rand()/(float)(RAND_MAX))*4; 
     printf("Sleeping for %d secs\n",stimqe); 
     sleep(stimqe); 

     printf("In what shall I fetch it, dear Liza, dear Liza? \n"); 
     printf("In what shall I fetch it, dear Liza, in what? \n"); 

     fflush(stdout); 
     int stimee=2+(rand()/(float)(RAND_MAX))*4; 
     printf("Sleeping for %d secs\n",stimee); 
     sleep(stimee); 

     printf("There's a hole in my bucket, dear Liza, dear Liza \n "); 
     printf("There's a hole in my bucket, dear Liza, a hole. \n "); 
     fflush(stdout); 

     //signal 
     operations[0].sem_op = 1; 
     retval = semop(id, operations, 1); 

    } 

    } 

} 
+2

TL; DR!請閱讀http://sscce.org/。 – 2013-03-25 08:05:05

+0

你可以創建一個最小的問題的例子嗎? – LtWorf 2013-03-25 08:09:53

+0

對不起,這將有助於輸出:桶裏有一個洞,親愛的麗莎,親愛的莉莎, 桶裏有一個洞,親愛的麗莎,一個洞。接着修補它,親愛的亨利,親愛的亨利,親愛的亨利 然後修補它,親愛的亨利,親愛的亨利,修補它。並繼續在兩個進程之間切換 – tarantino 2013-03-25 08:12:29

回答

0

Henry線程需要告訴Liza線程他已完成發送線。 一個簡單的方法來做到這一點是通過一個變量。

const int HENRY_DONE = 0; 
const inte LIZA_DONE = 1; 
volatile int flag = HENRY_DONE; 

請注意volatile關鍵字?它告訴編譯器不要將變量存儲在寄存器中,它必須每次從內存中讀取,因爲它可能會在外部進行修改(在本例中是由其他線程修改)。我還爲兩個狀態添加了兩個常量,只是爲了使代碼更易於閱讀。我想你可以用enum代替。它使代碼更漂亮一些(並且還減少了編寫代碼行flag = -32的機會)。

//critical section 
    printf("Then mend it, dear Henry, dear Henry, dear Henry, \n"); 
    printf("Then mend it, dear Henry, dear Henry, mend it. \n"); 

    fflush(stdout); 

    flag = LIZA_DONE; // Hand over to Henry 
    do { 
    sleep(1); // If we don't sleep at all, there will be a busy wait. If you want to sleep for shorter than 1 s use usleep (located in `unistd.h`). 
    } until (flag == HENRY_DONE); // Wait for Henry to complete his next line. 
    printf("With a straw, dear Henry, dear Henry, dear Henry, \n"); 
    printf("With a straw, dear Henry, dear Henry, with a straw. \n"); 

對Henrys部分也是這樣。

注:

上述解決方案要求flag被放置在這兩個LIZA和Henry可訪問的存儲器。如果使用線程,它將按原樣運行,但如果使用fork,則需要將flag放置在共享內存(example)中。

+0

我試圖實現你的例子,但爲某種原因,Liza和Henry的前兩行都是正確的,但在此之後,這些行被切換。它是這樣的:(亨利,麗莎,麗莎,亨利,麗莎,亨利等)可能是什麼原因? – 2015-03-16 22:27:32

+0

因爲我的答案是錯誤的 - 'fork'會給LIZA和HENRY自己的所有變量的副本,並且他們將無法檢測到其他人所做的更改。請參閱添加的註釋。 – 2015-03-17 08:17:58

0

信號量不會強制執行關鍵節的調度或排序,它們只用於資源鎖定。你想,可以認爲是什麼如下:

鑑於有序/有序集合數據和兩個「工人」與打印的內容流任務:

  1. 每個工人「等待」輪到自己
  2. 它獲得一個數據(例如,一個從鬆線)
  3. 它輸出數據到標準輸出
  4. 這表明其他工人操作已完成,並進入休眠/等待

如果將所有步驟1-4都視爲關鍵部分,即您的「資源」既是a)數據存儲和b)輸出流,信號量也足以解決此問題。要查看信號量用於資源鎖定的示例,請參閱dining philosophers problem

+0

嗨,我已經看過哲學家的哲學問題,它似乎運行類似於我的代碼。無論如何,你可以指向我的方向在我的代碼中的問題是@klas lindback說我需要涉及交接,但我不知道如何做到這一點 – tarantino 2013-03-26 00:22:56

相關問題