将数据从父进程传递到其子进程——IPC、UNIX
Pass data from parent process to its child process — IPC, UNIX
我正在尝试用 C for 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
问题出在逻辑上。去除样板代码后,逻辑如下:
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:parent 和 child 同时处理 运行。
他们中的任何一个都可以首先在 sem_wait
成功。如果 child 首先这样做,它会
从共享内存和 parent 打印出乱码的初始未初始化值
将被锁定,永远等待信号量。
尝试在等待信号量之前将虚数(或非虚数)的 sleep(1) 添加到 parent 中。
这将模拟处理器上下文切换。
问题 #2:你 wait/signal 只有一次。例如。你写下所有的值,然后才发出信号。
这就是为什么只打印最后一个值的原因。
问题 #3:Child 没有任何循环。他应该如何读取 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
我正在尝试用 C for 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
问题出在逻辑上。去除样板代码后,逻辑如下:
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:parent 和 child 同时处理 运行。
他们中的任何一个都可以首先在 sem_wait
成功。如果 child 首先这样做,它会
从共享内存和 parent 打印出乱码的初始未初始化值
将被锁定,永远等待信号量。
尝试在等待信号量之前将虚数(或非虚数)的 sleep(1) 添加到 parent 中。
这将模拟处理器上下文切换。
问题 #2:你 wait/signal 只有一次。例如。你写下所有的值,然后才发出信号。 这就是为什么只打印最后一个值的原因。
问题 #3:Child 没有任何循环。他应该如何读取 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