我目前正在玩信号量并尝试理解它们。我试图按照一个教程,要求我编辑示例代码,让程序运行两个进程,轮流将歌词输出到歌曲('There's a hole in the bucket')。
我的问题是,当我在程序中添加更多行的歌曲时,进程不会交替,但只有两行它们才能正常工作。
一个过程处理Liza的部分,另一个处理Henry的部分。这是我的代码:
#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);
}
}
}
答案 0 :(得分:0)
信号量不强制执行关键部分的调度或排序,它们仅用于资源锁定。您想要的可以被认为如下:
给定一个有序/有序的数据集和两个“工作人员”,负责将其内容打印到流中:
如果您将所有步骤1-4视为关键部分,即您的“资源”既a)数据存储又b)输出流,则信号量足以解决此问题。要查看信号量用于资源锁定的示例,请参阅dining philosophers problem。
答案 1 :(得分: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");
为亨利部分做同样的事。
注意:强>
上述解决方案要求flag
放在LIZA和HENRY都可以访问的内存中。如果您使用线程,它将按原样运行,但如果您使用fork
,则需要将flag
放在共享内存(example)中。