我正在尝试用C语言在Unix中创建一个程序。给定一个数组,我应该通过共享内存和使用信号量将数组的每个项从父进程传递给它的子进程。 这就是我所拥有的。
const key_t sem_key = (key_t)0x12345611;
const key_t shm_key = (key_t)0x12339611;
int sem_wait(int semafor_id)
{
struct sembuf sb;
sb.sem_num = 0;
sb.sem_op = -1;
sb.sem_flg = SEM_UNDO;
return semop(semafor_id, &sb, 1);
}
int sem_signal(int semafor_id)
{
struct sembuf sb;
sb.sem_num = 0;
sb.sem_op = 1;
sb.sem_flg = SEM_UNDO;
return semop(semafor_id, &sb, 1);
}
int main(int argc, char *argv[])
{
int status;
char str[3];
str[0] = 'z';
str[1] = 'x';
str[2] = 'y';
// Create shared memory
int memory_id = shmget(shm_key, 1, 0600 | IPC_CREAT | IPC_EXCL);
if (memory_id < 0)
{
printf("Shared memory creating failed\n");
return 1;
}
// Create semafor
int semafor_id = semget(sem_key, 10, 0600 | IPC_CREAT | IPC_EXCL);
if (semafor_id < 0)
{
printf("SEMAFOR creating failed\n");
return 1;
}
semctl(semafor_id, 0, SETVAL, 1); // init semafor
pid_t pid = fork();
if (pid < 0)
printf("FORK FAILED\n");
else if (pid > 0)
{
printf("PARENT\n");
void *address = shmat(memory_id, NULL, 0);
if (address == NULL)
{
printf("Failed to attach memory\n");
return 1;
}
if (sem_wait(semafor_id) < 0) // sem_wait() decrements (locks) the semaphore pointed to by sem.
{
printf("Failed wait parent\n");
return 1;
}
for (int i = 0; i < 3; i++)
{
void *address = shmat(memory_id, NULL, 0);
if (address == NULL)
{
printf("Failed to attach memory\n");
return 1;
}
printf("writer started.\n");
char *data = (char *) address;
*data = str[i];
printf("writer ended.\n");
}
if (shmdt(address) != 0)
printf("Failed to detach shared memory\n");
if (sem_signal(semafor_id) < 0)
printf("Failed signal parent\n");
else
printf("Parent leave generating number\n");
// wait for child
wait(&status);
printf("Destroy semafor\n");
semctl(semafor_id, 0, IPC_RMID, 0);
printf("Destroy shared memory\n");
shmctl(memory_id, IPC_RMID, 0);
return 0;
} // close parent case
else
{
printf("CHILD\n");
if (sem_wait(semafor_id) < 0)
printf("FAILED wait child\n");
else
{
void *address = shmat(memory_id, NULL, 0);
if (address == NULL)
{
printf("Failed to atach memory in child\n");
return 1;
}
char *data = (char *) address;
printf("Child read data %c\n", *data);
if (shmdt(address) != 0)
printf("Failed to detach shared memory in child\n");
}
}
if (sem_signal(semafor_id) < 0)
printf("Failed signal child\n");
else
printf("Leave data reading\n");
return 0;
}
目前的输出是:
writer started
writer ended
writer started
writer ended
writer started
writer ended
child read data y
destroy semafor
destroy shared memory
正如您所看到的那样,父对象在共享内存中写入3次,然后子进程获取共享内存的访问权限,打印共享内存的数据。 我想要的输出是:
writer started
writer ended
child read data z
writer started
writer ended
child read data x
writer started
writer ended
child read data y
destroy semafor
destroy shared memory
答案 0 :(得分:2)
问题在于逻辑。删除样板代码后,逻辑如下:
Get shared memory
Get semaphore with value 1
fork
in parent:
wait semaphore (problem #1, #2) <-- supposed to decrement it to 0
for(i=0;i<3;++i)
{
write next char <<-- no synchronization here :-(
}
signal semaphore
wait for child
STOP
in child:
wait semaphore (problem #1)
read next char
signal semaphore
(problem #3)
STOP
英文:
the writer acquires write lock
writes 3 values into the same location
then signals the reader to read data.
At this moment writer moves on to wait for child PID to die.
The reader reads the last value once
signals the semaphore
then exits.
At this moment writer sees reader died
cleans up
...and exits
问题#1:父进程和子进程同时并发运行。
他们中的任何一个都可以首先在sem_wait
成功。如果孩子首先这样做
从共享内存和父级打印出乱码的初始未初始化值
会被锁定等待信号量永远。
尝试在等待信号量之前将虚拟(或非)睡眠(1)添加到父级中。
这将模拟处理器上下文切换。
问题#2:你只等待/发出一次信号。例如。你写下所有的值,然后才发出信号。 这就是为什么只打印最后一个值。
问题#3:孩子没有任何循环。他怎么读3个值?!
逻辑应该是:
Writer
Do 3 times:
acquire write semaphore
write next value
signal reader semaphore
wait child to die
clean up
exit
reader:
Do 3 times:
acquire reader semaphore
read next value
signal writer semaphore
exit