信号量阻塞 children
Semaphore blocking children
我有一个问题,我想做一个 fork,例如一个 20 个进程的 fork,这个 fork 创建了,在最后一个没有创建之前不应该做任何事情,我想用信号量来做,如何我可以实现吗?
for (i=0; i<20; i++) {
switch (fork()) {
case: -1:
exit(EXIT_FAILURE);
case 0:
execve(....);
exit(EXIT_FAILURE);
default:
printf ("Child Created!");
}
}
这是你的作业。你可以稍后付钱给我。
#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);
}
这个想法很简单。将(必要的,共享的)信号量初始化为零,并让每个 child 在它做它的事情之前等待它。
当你在 parent 中完成分叉后,你 post 到信号量 20 次,以便每个 child 的 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 丑陋和需要设置一个 file-based 密钥,但是作为奖励,你可以将信号量增加 20一口气
我有一个问题,我想做一个 fork,例如一个 20 个进程的 fork,这个 fork 创建了,在最后一个没有创建之前不应该做任何事情,我想用信号量来做,如何我可以实现吗?
for (i=0; i<20; i++) {
switch (fork()) {
case: -1:
exit(EXIT_FAILURE);
case 0:
execve(....);
exit(EXIT_FAILURE);
default:
printf ("Child Created!");
}
}
这是你的作业。你可以稍后付钱给我。
#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);
}
这个想法很简单。将(必要的,共享的)信号量初始化为零,并让每个 child 在它做它的事情之前等待它。
当你在 parent 中完成分叉后,你 post 到信号量 20 次,以便每个 child 的 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 丑陋和需要设置一个 file-based 密钥,但是作为奖励,你可以将信号量增加 20一口气