Семафор блокирует детей
У меня проблема, я хотел бы сделать разветвление, например, разветвление из 20 процессов, созданное этим разветвлением, не должно ничего делать, пока не будет создан последний, и я хочу сделать это с семафором, как я могу это реализовать?
for (i=0; i<20; i++) {
switch (fork()) {
case: -1:
exit(EXIT_FAILURE);
case 0:
execve(....);
exit(EXIT_FAILURE);
default:
printf ("Child Created!");
}
}
1 ответ
Вот тебе домашнее задание. Вы можете заплатить мне позже.
#include <semaphore.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
sem_t *sem;
if(MAP_FAILED==(sem=mmap(0, sizeof(*sem), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0)))
{ perror("mmap"); exit(EXIT_FAILURE); }
if(0>sem_init(sem, 1/*shared*/, 0/*init val*/))
{ perror("sem_init"); exit(EXIT_FAILURE); }
for(int i=0; i<20; i++){
switch(fork()){
case -1: perror("fork"); /*you'll need to kill the children here*/
exit(EXIT_FAILURE);
case 0:
puts("waiting");
sem_wait(sem);
puts("running");
exit(0);
default:
puts("Child created");
}
}
puts("done forking. signalling children");
usleep(1000000);
for(int i=0; i<20; i++)
sem_post(sem);
}
Идея проста. Инициализируйте (обязательно разделяемый) семафор до нуля и заставьте каждого ребенка ждать его, прежде чем он сделает свое дело. Когда вы закончите разветвление в родителе, вы отправите сообщение на семафор 20 раз, чтобы каждый ребенок sem_wait
вызов завершен.
То же самое с семафорами SysV:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
//the manpage says we should define this union (as follows)
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
int main()
{
key_t key;
char tmpl[]="/tmp/XXXXXX";
{
int tmpfd;
if(0>(tmpfd = mkstemp(tmpl)))
{ perror("mkstemp"); exit(EXIT_FAILURE); }
close(tmpfd);
}
//Get a key
puts(tmpl);
key=ftok(tmpl, 'A');
int sem;
int ec = EXIT_SUCCESS;
if(0>(sem = semget(key, 1 /*1 sem*/, IPC_CREAT|IPC_EXCL|0600)))
{ perror("semget"); goto fail; }
if(0>semctl(sem, 0 /*ix*/, SETVAL, (union semun){ .val=0 }))
{ perror("sem init"); goto fail; }
for(int i=0; i<20; i++){
switch(fork()){
case -1: { perror("fork"); /*you'll need to kill the children here*/ exit(EXIT_FAILURE); }
case 0:
puts("waiting");
semop(sem, (struct sembuf[1]){{ .sem_op=-1 }}, 1);
puts("running");
exit(0);
default:
puts("Child created");
}
}
puts("done forking. signalling children");
usleep(1000000);
//can up it by 20 in one go
semop(sem, (struct sembuf[1]){{ .sem_op=+20 }}, 1);
goto success;
fail: ec = EXIT_FAILURE;
success:
semctl(sem, 0, IPC_RMID);
unlink(tmpl);
exit(ec);
}
Здесь вам придется потанцевать с уродством SysV IPC API и с необходимостью установить ключ на основе файла, но затем, в качестве награды, вы можете увеличить семафор на 20 за один раз.