2013-03-25 50 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

相关问题