[英]C++ Managing Processes
我有一个创建10个子进程的进程,它们全部共享一个内存段。 这10个子进程可以同时运行,但是我希望父亲在这段时间内睡觉。 孩子们吃完饭后就去睡觉。 当所有的孩子都做完之后,父亲进行一些计算并唤醒孩子们进行下一轮(然后他再次入睡,直到所有孩子都完成了计算)。 我以为我可以在一个以check_children_finished()为条件的while循环中暂停()。 孩子知道通过kill()向父母发出信号,他们有他的pid(作为参数发送给他们),而实际上父亲也有孩子pid(存储在共享内存中)这是一些代码-
父代码:
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cstring>
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
static void sig_usr(int);
static volatile sig_atomic_t *sharedArray;
static int segmentId;
int number_of_children = 10;
bool check_children_finished(){
for (int i=1; i<number_of_children; i++)
if (sharedArray[i*2] == -1)
return false;
return true;
}
void sig_usr (int signo)
{
/*
// This is signals handler (when a signal fires this is what runs)
// we expect SIGUSR1 from the child process
if(signo == SIGUSR1)
cout << "(parent: " << (int)getpid() << ") --- caught SIGUSR1" << endl;
if (signo == SIGUSR2){
cout << "(parent: " << (int)getpid() << ") --- caught SIGUSR2" << endl;
}else
perror("unexpected signal fired");
// return;
*/
}
int main()
{
// size of the shared memory array
int arrSize = 100;
const int shareSize = sizeof(sig_atomic_t) * (arrSize);
/* Allocate shared memory segment */
segmentId = shmget(IPC_PRIVATE, shareSize, S_IRUSR | S_IWUSR);
sharedArray = (sig_atomic_t *) shmat(segmentId, NULL, 0);
// feel shared memory with -1
for (int i=0; i<arrSize; i++)
sharedArray[i] = -1;
// binding SIGUSR1 & SIGUSR2 to sig_usr method
// we need to override SIGUSR2 because of group signaling
signal(SIGUSR1, sig_usr);
// signal(SIGUSR2,sig_usr);
fprintf(stderr, "\n (parnet) myPid=%d ; segId=%d\n",(int)getpid(), segmentId);
sharedArray[0] = 123;
int kids = 0; // this is the number of child processes
// we send to the child (as shell parameters) the parent pid, shared segment address , and index to the shared memory(this is where he will write his pid and in index+1 the heuristic value)
char* kidsParams[5];
// takes care of param[0]=command to run
string exec_line = "./child";
kidsParams[0] = new char[exec_line.size()+1];
memcpy(kidsParams[0], exec_line.c_str(), exec_line.size());
// takes care of param[1]=parent pid
kidsParams[1] = new char[100]; // = malloc(100*sizeof(char));
sprintf( kidsParams[1],"%d",(int)getpid());
// takes care of param[2]=shared mem segment address
kidsParams[2] = new char[100];
sprintf( kidsParams[2],"%d",segmentId);
// takes care of param[3]=the child private index in shared mem
kidsParams[3] = new char[100];
kidsParams[4] = NULL; // needed as end of array
int index = 0;
for(; kids<number_of_children; kids++) {
sprintf( kidsParams[3],"%d",index);
index+=2;
pid_t childpid = fork();
if(childpid==0){
execv(kidsParams[0],kidsParams);
}
}
cout << "(parent) --- just finished creating " << number_of_children << " kids" << endl;
cout << "(parent) entering to while {...} pause" << endl;
for (int i=0; i<number_of_children; i++)
cout << "[" << i << "] = " << sharedArray[i];
cout << endl;
// going to sleep --- here I want while loop with conditioning that all children finished
while ( ! check_children_finished() ) {
cout << "(parent) now will signal the group" << endl;
// killpg sends signal to the group (all the children). note that the group has the same pid as the father
killpg(getpid(),SIGUSR2);
cout << "(parent) just finished signaling the group" << endl;
pause();
for (int i=0; i<number_of_children; i++)
cout << "[" << i << "] = " << sharedArray[i];
cout << endl;
}
cout << "(parent) exited the while{...} paused" << endl;
// removes shared memory
// shmdt (sharedArray);
// shmctl (segmentId, IPC_RMID, NULL);
// note that all children must also shmctl (...IPC_RMID...);
}
这是一个子代码:
(same includes...)
using namespace std;
// declare the function proptotype (needed in signal function)
static void sig_usr(int);
// handles the signal (what happens when the signal fires) --- here I want to solve the search problem
void sig_usr (int signo)
{
/*
if(signo == SIGUSR1){
cout << "(child: " << (int)getpid() << ") --- caught SIGUSR1" << endl;
}else if(signo == SIGUSR2){
cout << "(child: " << (int)getpid() << ") --- caught SIGUSR2" << endl;
}else
perror("eerrrr");
// return;
*/
}
int main(int argc, char** argv){
// binding the signal to the handler
signal(SIGUSR2,sig_usr);
int segmentId;
volatile sig_atomic_t *sharedArray ;
int myIndex;
int myData = 5;
int parentPid;
// read parameters
parentPid = atoi(argv[1]);
segmentId = atoi(argv[2]);
myIndex = atoi(argv[3]);
// declare a pointer to the shared memory
sharedArray = (sig_atomic_t *) shmat(segmentId, NULL, 0);
sharedArray[myIndex] =(int)getpid();
sharedArray[myIndex+1] = myData;
// fprintf(stderr, "My Group Pid(child): %d\n",(int)getpgrp());
cout << "(child: " << (int)getpid() << ") --- going to sleep" << endl;
pause();
cout << "(child: " << (int)getpid() << ") --- I woke up" << endl;
//calc data
//fprintf(stderr, "My Pid(child): %d\n",(int)getpid());
//fprintf(stderr, "I got %d (child)\n",sharedArray[0] );
// this signals the father
kill(parentPid,SIGUSR1);
cout << "fired SIGUSR1"<< endl;
}
这是一个典型的输出:
(parnet) myPid=3104 ; segId=22872080
(parent) --- just finished creating 10 kids
(parent) entering to while {...} pause
[0] = 123[1] = -1[2] = -1[3] = -1[4] = -1[5] = -1[6] = -1[7] = -1[8] = -1[9] = -1
(parent) now will signal the group
User defined signal 2
有时我会得到类似:
(parnet) myPid=3126 ; segId=22937618
(child: 3129) --- going to sleep
(child: 3127) --- going to sleep
(parent) --- just finished creating 10 kids
(parent) entering to while {...} pause
[0] = 3127[1] = 5[2] = 3128[3] = 5[4] = 3129[5] = 5[6] = -1[7] = -1[8] = -1[9] = -1
(parent) now will signal the group
User defined signal 2
(child: 3127) --- I woke up
fired SIGUSR1
(child: 3128) --- going to sleep
(child: 3132) --- going to sleep
(child: 3129) --- I woke up
fired SIGUSR1
谁能提出解决方案? 谢谢! -利隆
我建议在监视进程和其他工作进程之间使用管道,并使用简单的文本协议进行控制通信。
(因为管道上的文本协议比信号更可靠-可以“丢失”或“合并”)
因此,在分叉工人之前,我会调用(例如10次,或者如果您希望双向访问,则可能是2 * 10次) pipe(2)创建控制通信。 然后,您可以使用ppoll(2) (或只是poll
)多路传输管道。
但你可以考虑使用现有的框架 ,例如像开放式MPI (的实现MPI =“消息传递接口”)。 这并不意味着放弃使用共享内存段(只需将MPI用于控制和同步问题)。 还是使用OpenMP或仅使用p线程 ?
MPI非常用于高性能数值计算中,许多超级计算机都具有MPI(使用专用硬件进行非常快速的消息传递)。
(当然,超级计算机是集群,因此,您实际上并没有在数千个内核之间共享内存;您可以通过在代码中仅使用MPI来利用它们。)
(您也可以通过OpenCL调查使用GPGPU)
同步过程的通常方法是使用信号量。
SysV使用semctl(),semop()和semget()提供更复杂的信号量操作。 POSIX信号量(更简单)使用sem_open(),sem_close(),sem_post()和sem_wait()。
无论使用哪种方法,在启动任何子进程之前都要在主进程中创建信号灯,并在退出主进程时在所有子进程都已收获之后删除该信号灯。
每个孩子都应在信号量上执行sem_open()(不使用O_CREAT),然后在sem_wait()处执行阻塞操作,前提是您已正确初始化了信号量。 当sem_wait()返回时,执行接触共享内存的代码,然后调用sem_post()。 这应该为您的共享内存段提供独占共享访问权限。
使用信号似乎是个坏主意。 我当然从未听说过这样做。
以我自己的经验,我有一个单独的过程来创建所有SysV信号量并将信号量ID复制到共享内存段中的适当位置。 这是所有处理过程,然后退出。 信号量是持久的-然后,我将从命令行启动其他进程,这些进程将打开信号量(不带O_CREAT)并执行sem_wait()。 因此,我没有使用fork / exec来启动子进程。 与命令行分开的过程似乎更简单。
我不确定进程子进程是否继承信号量ID,例如继承文件描述符
确实,使用信号量使事情变得更简单,并且最终可以工作。 请注意,您必须使用-pthread标志进行编译(例如g ++ -Wall -pthread chikd.c -o parent)。 我确实有一个小问题,有人知道我是否可以做得比sleep(1)更好的事? (父代码,第109行)。
父代码:
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cstring>
#include <string>
#include <sstream>
#include <iostream>
#include <semaphore.h>
#include <fcntl.h>
using namespace std;
char SEM_NAME[] = "lir";
static void sig_usr(int);
static sig_atomic_t *sharedArray; // static volatile sig_atomic_t *sharedArray;
static int segmentId;
int number_of_children = 10;
int child_init_ctrl = 0;
int child_finish_ctrl = 1;
int number_of_children_ctrl = 2;
int indexes_start_ctrl = 3;
// each child has its own : PID,DATA,ADDRESS_TO_HIS_INIT_STATE
int data_start = indexes_start_ctrl + number_of_children*3;
int getMyStartIndex(){
return -1;
}
void sig_usr (int signo) {}
int main() {
// create&init *new* semaphore
sem_t *mutex;
mutex = sem_open (SEM_NAME,O_CREAT,0644,1);
if(mutex == SEM_FAILED) {
perror("unable to create semaphore");
sem_unlink(SEM_NAME);
exit(-1);
}
// size of the shared memory array
int arrSize = 100;
const int shareSize = sizeof(sig_atomic_t) * (arrSize);
/* Allocate shared memory segment */
segmentId = shmget(IPC_PRIVATE, shareSize, S_IRUSR | S_IWUSR);
sharedArray = (sig_atomic_t *) shmat(segmentId, NULL, 0);
// fill shared memory with -1
for (int i=0; i<arrSize; i++)
sharedArray[i] = -1;
// binding SIGUSR1 & SIGUSR2 to sig_usr method
// we need to override SIGUSR2 because of group signaling
signal(SIGUSR1, sig_usr);
signal(SIGUSR2,sig_usr);
sem_wait(mutex);
sharedArray[child_init_ctrl] = 0;
sharedArray[child_finish_ctrl] = 0;
sharedArray[number_of_children_ctrl] = number_of_children;
sem_post(mutex);
// we send to the child (as shell parameters) the parent pid, shared segment address , and index to the shared memory(this is where he will write his pid and in index+1 the heuristic value)
char* kidsParams[6];
// takes care of param[0]=command to run
string exec_line = "./child";
kidsParams[0] = new char[exec_line.size()+1];
memcpy(kidsParams[0], exec_line.c_str(), exec_line.size());
// takes care of param[1]=parent pid
kidsParams[1] = new char[100]; // = malloc(100*sizeof(char));
sprintf( kidsParams[1],"%d",(int)getpid());
// takes care of param[2]=shared mem segment address
kidsParams[2] = new char[100];
sprintf( kidsParams[2],"%d",segmentId);
// takes care of param[3]=the child private index in shared mem
kidsParams[3] = new char[100];
// takes care of param[4]=the child's first index of start state
kidsParams[4] = new char[100]; // = malloc(100*sizeof(char));
sprintf( kidsParams[4],"%d",getMyStartIndex());
kidsParams[5] = NULL; // needed as end of array
// creates the child processes (and update child private index)
int index = 3;
for(int kids=0; kids<number_of_children; kids++) {
sprintf( kidsParams[3],"%d",index);
index+=3;
pid_t childpid = fork();
if(childpid==0){
execv(kidsParams[0],kidsParams);
}
}
while ( sharedArray[child_init_ctrl] != number_of_children ) {
// waiting on the CPU !!! or going to sleep. is there a better solution?
sleep(1);
}
// killpg sends signal to the group (all the children). note that the group has the same pid as the father
killpg (getpid(),SIGUSR2);
// going to sleep --- here I want while loop with conditioning that all children finished
bool all_child_finished_flag = false;
while ( all_child_finished_flag == false ) {
sem_wait(mutex);
if (sharedArray[child_finish_ctrl] == number_of_children)
all_child_finished_flag = true;
sem_post(mutex);
if (all_child_finished_flag == false)
pause();
}
// removes shared memory and delete semaphore
shmdt (sharedArray);
shmctl (segmentId, IPC_RMID, NULL);
// note that all children must also shmctl (...IPC_RMID...);
// removes the mutex
sem_close(mutex);
sem_unlink(SEM_NAME);
}
子代码:
// declare the function proptotype (needed in signal function)
static void sig_usr(int);
int child_init_ctrl = 0;
int child_finish_ctrl = 1;
int number_of_children_ctrl = 2;
int number_of_children=0;
// handles the signal (what happens when the signal fires)
void sig_usr (int signo) {}
char SEM_NAME[] = "lir";
int main(int argc, char** argv) {
(same includes...)
// create&init *existing* semaphore
sem_t *mutex;
mutex = sem_open (SEM_NAME, 0, 0644, 0);
if(mutex == SEM_FAILED) {
perror("reader:unable to execute semaphore");
sem_close(mutex);
exit(-1);
}
// binding the signal to the handler
signal(SIGUSR2,sig_usr);
volatile sig_atomic_t *sharedArray ;
int myData=0;
// read parameters
int parentPid = atoi(argv[1]);
int segmentId = atoi(argv[2]);
int myIndex = atoi(argv[3]);
int myStartState = atoi(argv[4]);
// declare a pointer to the shared memory
sharedArray = (sig_atomic_t *) shmat(segmentId, NULL, 0);
sharedArray[myIndex] =(int)getpid();
sharedArray[myIndex+1] = myData;
number_of_children = sharedArray[number_of_children_ctrl];
sem_wait(mutex);
sharedArray[child_init_ctrl]++;
sem_post(mutex);
pause();
// do some "calculations"
sharedArray[myIndex+1] = myIndex;
for (int i=0; i<10; i++)
sharedArray[myIndex+1] += i;
// this signals the father
bool should_i_fire = false;
sem_wait(mutex);
sharedArray[child_finish_ctrl]++;
if (sharedArray[child_finish_ctrl] == number_of_children)
should_i_fire = true;
sem_post(mutex);
if (should_i_fire == true)
kill(parentPid,SIGUSR1);
}
最好-Liron
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.