Managing Processes

Hi,

I have one process to create 10 sub-processes and they all share a memory segment. the 10 sub-processes can run concurrently, but the father has to sleep. Then the father makes some calculations and wakes the children for another round (and he again goes to sleep, until all children have finished their calculations). I figured out I can pause() inside a while loop that is conditioned on check_children_finished(). Here is some code -

Parent code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122

#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...);

}



Child code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
***********************

#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;

// 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;
}


A typical output would look like:

1
2
3
4
5
6
7

 (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


Sometimes I get something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

 (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


Can anyone suggest a solution? Thanks!

-- Liron
memcpy(kidsParams[0], exec_line.c_str(), exec_line.size());
What's wrong with strncpy()?

You have a race condition.

The parent creates the children does some stuff and closes. The children start up and do thier thing, but the parent dies before they get started, except every now and then a child gets scheduled to go far enough to write to the console.

You should sleep() in the parent to allow the children to start up, or sync somehow.
Last edited on
Topic archived. No new replies allowed.