I would like to ask you guys some help with C programming. Basically Im having issues with fork() system call.
Here's my question:
We have a Manager Process which has to create POP_SIZE Student processes. Manager Process and Student Processes itself cannot do anything else until all Student Processes have been created.
Every Student Process is identified by:
1) its identification number (6-digit integer)
2) grade obtained in specific exam (integer)
Here's the code I managed to write:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#define POP_SIZE 10
int main(int argc, char *argv[]){
pid_t firstFork;
int *status;
int numStudents = 0;
pid_t managerChild, managerParent;
pid_t students[POP_SIZE];
int studentStatus[POP_SIZE];
switch(firstFork = fork()){
case -1:
perror("Something wrong with fork()\n");
break;
case 0:
managerChild = getpid();
printf("Manager Child Process %d started\n", managerChild);
printf("I have to create %d Student Processes\n", POP_SIZE);
for(int i = 0; i < POP_SIZE; i++){
switch(students[i] = fork()){
case -1:
perror("Something wrong with FORK in Manager Child Process\n");
break;
case 0:
printf("Created first Student Process PID: %d\n", getpid());
numStudents++;
break;
default:
printf("Haven't created all Student Processes\n");
waitpid(managerChild, status, WUNTRACED | WNOHANG);
printf("%d Student Processes succesfully created\n", numStudents);
break;
}
}
break;
default:
for(int i = 0; i < POP_SIZE; i++)
wait(NULL);
}
}
I'd need some help in understanding where to put wait(*status) or waitpid(pid, *status, __options) functions in my code in order to achieve my requirements specified above?
Moreover, how can I assign and keep storing of variables for every single process?
Thank you very much
Since you will be creating many child processes, it is best to start by creating a function that creates the child process, and has it execute a function specified by the caller. Let's assume both the ID number and grade are ints. Then,
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
/* Run func(id, grade) in a child process.
Returns the child process PID if success,
or -1 with errno set in case an error occurs.
*/
pid_t run_child(int id, int grade,
int (*func)(int id, int grade))
{
pid_t p;
p = fork();
if (p == -1) {
/* fork() failed; it set errno to indicate the error. */
return -1;
} else
if (!p) {
/* Run child process function. When it returns,
have the child exit with that exit status. */
exit(func(id, grade));
} else {
/* Parent process. p is positive. */
return p;
}
}
Note that the third parameter is a function pointer. We specify it using the function name. That function must take two int parameters (the ID and the grade, respectively), and return an int. For example:
/* Each child process runs this function.
*/
int child_process(int id, int grade)
{
printf("Child: id = %d, grade = %d, PID = %d.\n", id, grade, (int)getpid());
return EXIT_SUCCESS;
}
We can create a child process that runs that function using child_pid = run_child(123456, 5, child_process);. Note how the name of the function can be used to specify a function pointer. The standard C qsort() function uses the exact same mechanism to allow one to quicksort anything; the caller just needs to specify a function that can compare two elements in the array to be sorted.
We will be creating several children, and reaping them at once. That means it makes sense to write a function that reaps all child processes, essentially blocking until they all exit. We are likely interested in the exit statuses of at least some of them, so let's pass the interesting child processes PIDs, ints to save the status to, and the number of processes in those arrays, as parameters:
/* Reap all child processes.
If child_count > 0, child processes with PID in child_pid[]
will have child_pid[] negated when reaped, with exit status saved
in child_status.
The function returns the number of child processes reaped.
*/
size_t reap_children(pid_t *child_pid, int *child_status, size_t child_count)
{
size_t reaped = 0;
size_t i;
int status;
pid_t p;
while (1) {
/* Reap a child process, if any. */
p = wait(&status);
if (p == -1) {
/* errno == EINTR is not an error; it occurs when a
signal is delivered to a hander installed without
SA_RESTART flag. This will not occur in this program,
but it is good practice to handle that case gracefully. */
if (errno == EINTR)
continue;
/* errno set by wait(). */
return reaped;
}
/* Another child process was reaped. */
reaped++;
/* If the reaped child was one of the interesting ones,
negate its pid and save the exit status. */
for (i = 0; i < child_count; i++) {
if (child_pid[i] == p) {
child_pid[i] = -p;
child_status[i] = status;
break;
}
}
}
}
Note that p = wait(&status) reaps a child process. This means that if one or more child processes have already exited, it picks one of them, and returns its PID, with exit status saved to &status. If all child processes left are still running, the call will wait until at least one of them exits. If there are no more child processes, it returns -1 with errno set to ECHILD.
If signal handlers were used, wait() can also return -1 with errno set to EINTR, if a signal was delivered to a signal handler that was installed without the SA_RESTART flag with sigaction(). Many programmers forgo this check (because "it'll never happen"), but I do like to include that check because it is easy, and makes sure adding signal handling to my code won't bite me in the butt later on. I very often do, too. (Add signal handling, I mean.)
The reason we negate the pids when the respective child process is reaped, is simple: it allows us to easily detect which child processes were reaped. (POSIX says all process IDs are positive, and pid_t is a signed type. Negating a PID is a commonly used technique, too; just see e.g. waitpid().)
If we wanted to reap a specific child process, we'd use waitpid(). For example,
pid_t child, p; /* wait for 'child'. */
int status;
do {
p = waitpid(child, &status, 0);
if (p == -1) {
if (errno == EINTR)
continue;
break;
}
} while (p != child);
if (p == child) {
/* Reaped 'child', status in 'status'. */
} else {
/* Error: failed to reap 'child'. See 'strerror(errno)'. */
}
Do note that in POSIX/Unix terminology 'child process' refers to processes created by this process only; not "grandchildren", processes created by child processes.
I prefer to write my processes to take in parameters from the command line. If no parameters are specified, or -h or --help is specified, a short help ("usage") is displayed; this is extremely common in POSIX and Unix command-line tools, and therefore very intuitive.
The following main() takes one or more ID:grade as command-line parameters. For each one, it creates a child process, and has it run the child_process() function with the specified ID and grade. The main program will then reap them all, and describe the exit status of each child process.
int main(int argc, char *argv[])
{
pid_t child_pid[argc];
int child_status[argc];
int count, i, n, arg, id, grade, status;
char dummy;
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s ID:GRADE [ ID:GRADE ]*\n", argv[0]);
fprintf(stderr, "\n");
return EXIT_SUCCESS;
}
status = EXIT_SUCCESS;
count = 0;
for (arg = 1; arg < argc; arg++) {
if (sscanf(argv[arg], "%d:%d %c", &id, &grade, &dummy) == 2) {
child_pid[count] = run_child(id, grade, child_process);
if (child_pid[count] == -1) {
fprintf(stderr, "Cannot fork a child process: %s.\n", strerror(errno));
status = EXIT_FAILURE;
} else
count++;
} else {
fprintf(stderr, "%s: Not a valid ID:GRADE specification.\n", argv[arg]);
status = EXIT_FAILURE;
}
}
if (count < 0) {
fprintf(stderr, "No running child processes.\n");
return EXIT_FAILURE;
}
n = reap_children(child_pid, child_status, count);
printf("Reaped %d child processes.\n", n);
for (i = 0; i < count; i++) {
if (child_pid[i] < 0) {
printf("Child process %d (%d of %d)", (int)(-child_pid[i]), i + 1, count);
if (WIFEXITED(child_status[i])) {
if (WEXITSTATUS(child_status[i]) == EXIT_SUCCESS)
printf(" exited with success (EXIT_SUCCESS), %d.\n", EXIT_SUCCESS);
else
if (WEXITSTATUS(child_status[i]) == EXIT_FAILURE)
printf(" exited with failure (EXIT_FAILURE), %d.\n", EXIT_FAILURE);
else
printf(" exited with status %d.\n", WEXITSTATUS(child_status[i]));
} else
if (WIFSIGNALED(child_status[i])) {
printf(" died from signal %d.\n", WTERMSIG(child_status[i]));
} else {
printf(" died from unknown causes.\n");
}
} else {
printf("Child process %d (%d of %d) was lost!\n", (int)child_pid[i], i + 1, count);
}
}
return status;
}
If you save the above as example.c, you can compile it to example using e.g.
gcc -Wall -O2 example.c -o example
If you then run say
./example 100001:1 100002:5 100003:3 21532:4
the output will be something like
Child: id = 100002, grade = 5, PID = 1260.
Child: id = 100001, grade = 1, PID = 1259.
Child: id = 100003, grade = 3, PID = 1261.
Child: id = 21532, grade = 4, PID = 1262.
Reaped 4 child processes.
Child process 1259 (1 of 4) exited with success (EXIT_SUCCESS), 0.
Child process 1260 (2 of 4) exited with success (EXIT_SUCCESS), 0.
Child process 1261 (3 of 4) exited with success (EXIT_SUCCESS), 0.
Child process 1262 (4 of 4) exited with success (EXIT_SUCCESS), 0.
Note that the initial Child: lines can be in any order, because the child processes run essentially in parallel. Each child process runs as soon as it is started, so this example is not a copy-and-paste answer to OP's requirements.
If you want to experiment with complex process hierarchies, I recommend using Graphviz to visualize them. For example, dot-kids.c:
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
static void reap_all(void)
{
pid_t p;
int status;
while (1) {
p = wait(&status);
if (p == -1) {
if (errno == EINTR)
continue;
if (errno == ECHILD)
return;
fprintf(stderr, "Process %d: reap_all(): %s.\n", (int)getpid(), strerror(errno));
return;
}
printf(" \"%d\" -> \"%d\" [ color=\"#ff0000\" ];\n", (int)p, (int)getpid());
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) == EXIT_SUCCESS)
printf(" \"%d\" [ label=\"%d\" ];\n", (int)p, (int)p);
else
printf(" \"%d\" [ label=\"%d (exit %d)\" ];\n", (int)p, (int)p, WEXITSTATUS(status));
} else
if (WIFSIGNALED(status))
printf(" \"%d\" [ label=\"%d (signal %d)\" ];\n", (int)p, (int)p, WTERMSIG(status));
else
printf(" \"%d\" [ label=\"%d (lost)\" ];\n", (int)p, (int)p);
fflush(stdout);
}
}
static pid_t run_child(int (*child)(int depth, int width), int depth, int width)
{
pid_t p;
fflush(stdout);
fflush(stderr);
p = fork();
if (p == -1) {
fprintf(stderr, "Process %d: Cannot fork: %s.\n", (int)getpid(), strerror(errno));
return -1;
} else
if (!p) {
exit(child(depth, width));
} else {
printf(" \"%d\" -> \"%d\" [ color=\"#0000ff\" ];\n", (int)getpid(), (int)p);
fflush(stdout);
return p;
}
}
int child(int depth, int width)
{
if (depth > 0) {
while (width > 0)
run_child(child, depth - 1, width--);
reap_all();
}
return EXIT_SUCCESS;
}
int main(int argc, char *argv[])
{
int depth, width, i;
char dummy;
if (argc != 3 || !strcmp(argv[1], "-h") || !strcmp(argv[2], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s depth width | dot -Tx11\n", argv[0]);
fprintf(stderr, "\n");
return EXIT_SUCCESS;
}
if (sscanf(argv[1], " %d %c", &depth, &dummy) != 1 || depth < 0) {
fprintf(stderr, "%s: Invalid depth.\n", argv[1]);
return EXIT_FAILURE;
}
if (sscanf(argv[2], " %d %c", &width, &dummy) != 1 || width < 1) {
fprintf(stderr, "%s: Invalid width.\n", argv[2]);
return EXIT_FAILURE;
}
printf("digraph {\n");
printf(" \"%d\" [ shape=\"box\", label=\"%d\" ];\n", (int)getpid(), (int)getpid());
fflush(stdout);
for (i = 0; i < width; i++)
run_child(child, depth, width - 1);
reap_all();
printf("}\n");
return EXIT_SUCCESS;
}
Compile it using e.g.
gcc -Wall -O2 dot-kids.c -o dot-kids
and run using e.g.
./dot-kids 1 3 | dot -Tx11
to see a process graph similar to
where the numbers are process IDs, blue arrows show which process created which, and red arrows show which process reaped which.
I think there are some mistakes in your code. The output I get is something like:
5 Student Processes succesfully created
Haven't created all Student Processes
Haven't created all Student Processes
3 Student Processes succesfully created
4 Student Processes succesfully created
Created first Student Process PID: 11436
Created first Student Process PID: 11438
Created first Student Process PID: 11437
Haven't created all Student Processes
4 Student Processes succesfully created
Haven't created all Student Processes
3 Student Processes succesfully created
Created first Student Process PID: 11439
Haven't created all Student Processes
3 Student Processes succesfully created
Created first Student Process PID: 11440
Haven't created all Student Processes
3 Student Processes succesfully created
Created first Student Process PID: 11441
Haven't created all Student Processes
2 Student Processes succesfully created
Created first Student Process PID: 11442
Created first Student Process PID: 11443
You see there are too much children executing, so this should make you suspicious (paricularly note that sometimes the number for the student processes seems decreasing from print to print). The parent will continue executing the for loop. However the child continues executing from the point where the fork is called and being it inside a loop, it will fork too creating another child and so on and so on. To avoid that you need a break from the for loop for the children processes.
You can try something like the following. I added a variable jj that if <0 means it is a child process executing. Before next loop iteration the variable is checked and if <0 it breaks from the for loop.
It is not the most elegant solution but seems ok.
#include<stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#define POP_SIZE 10
int main(int argc, char *argv[]){
pid_t firstFork;
int *status;
int numStudents = 0;
pid_t managerChild, managerParent;
pid_t students[POP_SIZE];
int studentStatus[POP_SIZE];
switch(firstFork = fork()){
case -1:
printf("Something wrong with fork()\n");
break;
case 0:
managerChild = getpid();
printf("Manager Child Process %d started\n", managerChild);
printf("I have to create %d Student Processes\n", POP_SIZE);
int jj = 0;
for(int i = 0; i < POP_SIZE; i++){
switch(students[i] = fork()){
case -1:
printf("Something wrong with FORK in Manager Child Process\n");
jj = -1;
break;
case 0:
printf("Created first Student Process PID: %d\n", getpid());
numStudents++;
jj = -1;
break;
default:
printf("Haven't created all Student Processes\n");
waitpid(managerChild, status, WUNTRACED | WNOHANG);
printf("%d Student Processes succesfully created\n", numStudents);
break;
}
if (jj<0) break;
}
break;
default:
for(int i = 0; i < POP_SIZE; i++)
wait(NULL);
}
}
I am trying to understand fork, sleep... commmands.
I want to do 4 children and one parent operation exactly in this order. Parent> child1> child4> child2> child3.
The tasks of these processes are as I wrote in the code below. In this code I have 1 parent, 3 child and 1 grandson(child4 is a grandson). How can I make transactions in this order? I tried to put a sleep on each if's but the program finished without waiting for input in child2.
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(void)
{
int n1 = fork();
int n2 = fork();
int input;
if (n1 > 0 && n2 > 0) {
int n3=fork();
if(n3==0)
{ //3th child
printf("3th child process id is %d (parent: %d) \n", getpid(),getppid());
if(input == getppid()) {
printf("matched!\n"); }
else {
printf("not matched!\n"); }
printf("program ended\n");
}
else {
printf("parent process id is %d (parent: %d)\n", getpid(),getppid());
sleep(1);
}
}
else if (n1 == 0 && n2 > 0)
{
printf("1th child process id is %d (parent: %d)\n",getpid(),getppid());
FILE * fp;
fp = fopen ("xx.txt", "w+");
printf("file was created...\n");
sleep(1);
}
else if (n1 > 0 && n2 == 0)
{
printf("2th child process id is %d (parent: %d) \n", getpid(),getppid());
printf("Enter a key: \n");
scanf("%d",&input);
FILE * fp;
fp = fopen ("xx.txt", "w+");
fprintf(fp, "%d", input);
printf("input has been written to the txt file!\n");
}
else {
//4th child
printf("4th child grandson process id is %d (parent: %d)\n", getpid(),getppid());
printf("say me password!\n");
}
return (0);
}
You could try something like:
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(void)
{
const size_t nb_child = 3;
size_t children_count = nb_child;
while (children_count > 0) {
int pid = fork();
if (pid == 0) {
printf("child process id is %d (parent: %d) \n", getpid(),getppid());
if (children_count == 1) {
int pid2 = fork();
if (pid2 == 0) {
printf("child process id is %d (parent: %d) \n", getpid(),getppid());
sleep(2);
} else
wait(NULL);
}
return 0;
} else {
//father
}
children_count--;
}
while (children_count != nb_child) {
wait(NULL);
children_count++;
}
return 0;
}
The "difficult" part is to wait for all children before exiting
Hello I am writing a c program which runs then waits for it to complete then executes an if condition. However after the child process completes it does not execute the rest of code in parent. Any advice would be great. Thanks
AA
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
int main() {
int D, waitVal3, waitVal4;
D = fork();
if(D == 0)
{
execv("DD", 0);
}
if(D != 0)
{
printf("\nPid = %d Code AA: created proccess Pid = %d (code DD)\n", getpid(), D);
}
waitVal3 = (waitVal4);
//NEVER ENTERS THIS CONDITION
printf("WAIT VAL: %d", waitVal3);
if(waitVal3 == D)
{
printf("\nPid = %d Code AA: process Pid = %d terminated\n", getpid(), D);
}
return 0;
}
DD
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
int main (int argc, char *argBB[]) {
int C3, waitVal, waitVal2, ps;
C3 = fork();
if(C3 != 0)
{
printf("\nPid = %d Code DD: created proccess Pid = %d (code CC)\n", getpid(), C3);
}
if( C3 == 0 )
{
execv("CC", 0);
printf("\nexecv failed\n");
exit(0);
}
if(C3 < 0)
{
printf("Fork failed");
exit(1);
}
ps = fork();
if(ps != 0)
{
printf("\nPid = %d Code DD: created proccess Pid = %d (code ps)\n", getpid(), ps);
}
if( ps == 0 )
{
char command[50];
strcpy(command, "ps -u username");
system(command);
exit(11);
kill(ps, SIGKILL);//KILL PROCCESS PS HERE
}
waitVal = wait(waitVal2);
if(waitVal == ps)
{
printf("\nPid= %d Code DD: process Pid = %d terminated\n", getpid(), ps);
printf("\nPid = %d Code DD: killing process Pid = %d\n", getpid(), C3);
kill(C3, SIGKILL);
printf("\nPid= %d Code DD: process Pid = %d terminated\n", getpid(), C3);
printf("\nPid = %d Code DD: terminating\n", getpid());
exit(7);
}
return 0;
}
You didn't call wait() and your execv() was incorrect...
... compare this with your version to check the differences...
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <string.h>
#include <sys/wait.h>
#include <errno.h>
int main() {
char *args[2] = {"DD", NULL};
int D, waitVal3, waitVal4, rc, waitStatus;
D = fork();
if ( D == -1 )
{
printf("fork failed\n");
exit(1);
}
if(D == 0)
{
// ORIG: execv("DD", args);
rc = execv("/some/path/to/DD", args);
printf("execv failed: errno: %d\n", errno);
exit(1);
}
if(D != 0)
{
printf("\nPid = %d Code AA: created proccess Pid = %d (code DD)\n", getpid(), D);
}
waitVal4 = wait(&waitStatus);
waitVal3 = (waitVal4);
//ORIGINALLY - NEVER ENTERS THIS CONDITION
printf("WAIT VAL: %d", waitVal3);
if(waitVal3 == D)
{
printf("\nPid = %d Code AA: process Pid = %d terminated\n", getpid(), D);
}
return 0;
}
I tried to come up with a solution using waitpid() instead of wait().
Why this didn't work?
int main() {
char *args[2] = {"DD", NULL};
int waitVal3, waitVal4, rc, waitStatus;
pid_t D;
D = fork();
if ( D == -1 )
{
printf("fork failed\n");
exit(1);
}
if(D == 0)
{
// ORIG: execv("DD", args);
if( execv("/home/ubuntu/workspace/C/DD", args) == -1 ){
printf("execv failed: errno: %d\n", errno);
exit(1);
}
if( waitpid( D, &waitStatus, 0 ) == -1 ){
printf("Error waiting child process.\n");
exit(1);
};
printf("\nPid = %d Code AA: process Pid = %d terminated\n", getpid(), D);
}
return 0;
}
Observation:
If I put the waitid() statement outside the child process, this works.
The following code worked:
if(D == 0)
{
// ORIG: execv("DD", args);
if( execv("/home/ubuntu/workspace/C/DD", args) == -1 ){
printf("execv failed: errno: %d\n", errno);
exit(1);
}
}
if( waitpid( D, &waitStatus, 0 ) == -1 ){
printf("Error waiting child process.\n");
exit(1);
};
printf("\nPid = %d Code AA: process Pid = %d terminated\n", getpid(), D);
This means that the parent process was able detect the termination of child process in this case. My understanding is that waitpid() should work whether
in child or parent process. I am firm believer that it did work. However, the consequent printf() statement in the child process didn't get executed since the child process got terminated.
Im new in C programming and i have to do this:
Write a program that creates a second process, and then in both processes outputs the process ID and the owners user ID.
I don't know if thats right and how to continue from here. Here is what i have:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(void) {
int ChildPID;
printf("This is the parent process number %d\n",getpid());
if ((ChildPID = fork()) == -1) {
perror("Could not fork");
exit(EXIT_FAILURE);
}
if (ChildPID == 0) {
//----In the child process
printf("This is the child process, number %d parent number %d\n", getpid(), getppid());
}
return(EXIT_SUCCESS);
}
The piece of code given below gives your solution. Here you can clearly identify parent code and child process code. Both are printing their corresponding pids.
void ExecuteChild(void);
void ExecuteParent(void);
int main(void)
{
pid_t pid;
pid = fork();
if (pid == 0)
ExecuteChild();
else
ExecuteParent();
}
void ExecuteChild(void)
{
int i;
for (i = 1; i <= 200; i++)
printf("CHILD[%d]: UserID[%d] printing - %d\n", getpid(),getuid(),i);
printf(" ------------- Child Exiting -------------\n");
}
void ExecuteParent(void)
{
int i;
for (i = 1; i <= 200; i++)
printf("PARENT[%d]: UserID[%d] printing - %d\n", getpid(),getuid(),i);
printf(" ------------- Parent Exiting -------------\n");
}
what I want is this:
1 main process that create 4 children process where:
-> The main process receive messages from the children through the queue and print the message recieved.
-> The children send messages (a string with priority+message) through the queue and finish.
All in a while (1), so, when you CTRL+C, the children finish first (the signal is in the children code) and then, the parent finish.
For the moment, I am having problem with mq_send() and mq_recieve().
Well, this is my code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <mqueue.h>
void sigint_handler()
{
/*do something*/
printf("killing process %d\n",getpid());
exit(0);
}
int main ()
{
mqd_t mqd;
struct mq_attr atributos;
// atributos.mq_maxmsg = 10;
//
// atributos.mq_msgsize = 50;
printf ("This is the parent. PID=%d\n",getpid ());
int num_children = 4;
int i;
int pid;
int status;
char buffer [50];
while (1){
for (i=0; i<num_children ;i++){
if ((pid=fork()==0)){
signal(SIGINT, sigint_handler);
int prio = rand () % 3;
printf ("%d\n",prio);
char * msg= "Hi dude";
char * priority=NULL;
if (prio == 0){
priority = "NORMAL";
}
else {
priority = "URGENT";
}
char* toSend=NULL;
toSend = malloc(strlen(msg)+1+strlen(priority));
strcpy (toSend,priority);
strcat (toSend,msg);
printf ("%s\n",toSend);
if ((mqd=mq_open("/queue.txt", O_CREAT|O_WRONLY, 0777, &atributos))==-1){
printf ("Error mq_open\n");
exit(-1);
}
if (mq_send(mqd, msg , strlen(toSend), prio) == -1) {
printf ("Error mq_send\n");
exit (-1);
}
mq_close(mqd);
printf ("This is children %d\n",getpid());
sleep(1);
exit(0);
}
}
if ((mqd=mq_open("/queue.txt", O_CREAT|O_WRONLY, 0777, &atributos))==-1){
printf ("Error mq_open\n");
exit(-1);
}
//Rest Parent code
if (mq_receive(mqd, buffer, strlen(buffer),0)==-1){
printf ("Error mq_recieve\n");
exit(-1);
}
printf("Received: %s\n",buffer);
sleep (1);
waitpid(pid,&status,0);
printf ("This is the parent again %d, children should have finished\n",getpid());
mq_close(mqd);
}
}
I don't know why both mq_send() and mq_receive() returns -1, what am I doing wrong¿?
And you you see something wrong in my code in order to do what I intend apart from the error I am talking about, let me know.
Thank you in advance, I appreciate any help.
user58697 touched upon the biggest problems.
(1) Your queue opens were failing with EINVAL because you wee passing uninitialized attributes because you commented out assignments.
(2) You were opening both queues for write-only. The parent queue needed to be opened in read mode.
(3) Execute permissions don't mean anything to a queue so 777 permissions while not invalid are unnecessary.
(4) Your sends/receives were failing because of invalid lengths. In many if not most cases it is just easier and safer to allocate your buffers to the length attribute of the queue. In this case you know the length before hand but in programs that don't you can get the value via mq_getattr.
(5) You weren't calling srand to seed the RNG before calling rand.
(6) You had a memory leak where you allocate space (unnecessarily) for the message but never freed it.
(7) What you were trying to do with passing priorities is redundant. POSIX MQs have priorities already built in. You can just use those.
I took out some of the fluff (mainly the loops & signals) to concentrate more on the queue aspects of your program.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
#include <mqueue.h>
int main()
{
srand(time(NULL));
mqd_t mqd;
struct mq_attr atributos = {.mq_maxmsg = 10, .mq_msgsize = 50};
int i;
int pid;
int status;
int num_children = 4;
char buffer[atributos.mq_msgsize];
for (i = 0; i < num_children; i++)
{
if ((pid = fork() == 0))
{
int prio = rand () % 3;
char* msg = "Hi dude";
strncpy (buffer, msg, sizeof(buffer));
if ((mqd = mq_open("/queue.txt", O_CREAT | O_WRONLY, 0666, &atributos)) == -1)
{
perror("child mq_open");
exit(1);
}
if (mq_send(mqd, buffer, sizeof(buffer), prio) == -1)
{
perror("mq_send");
exit(1);
}
mq_close(mqd);
exit(0);
}
}
// parent
if ((mqd = mq_open("/queue.txt", O_CREAT | O_RDONLY, 0666, &atributos)) == -1)
{
perror("parent mq_open");
exit(1);
}
int priority;
for (int i = 0; i < num_children; ++i)
{
if (mq_receive(mqd, buffer, sizeof(buffer), &priority) == -1)
{
perror("mq_recieve");
exit(1);
}
printf("Received (%s): %s\n", (priority == 0) ? "NORMAL" : "URGENT", buffer);
pid_t childpid;
if ((childpid = waitpid(-1, &status, 0)) > 0)
{
if (WIFEXITED(status))
printf("PID %d exited normally. Exit status: %d\n",
childpid, WEXITSTATUS(status));
else
if (WIFSTOPPED(status))
printf("PID %d was stopped by %d\n",
childpid, WSTOPSIG(status));
else
if (WIFSIGNALED(status))
printf("PID %d exited due to signal %d\n.",
childpid,
WTERMSIG(status));
}
}
mq_close(mqd);
}
First and foremost, when a system call fails, print errno (and strerror(errno)).
Now, obvious mistakes:
as was mentioned, you need a read access to be able to mq_receive()
what is strlen(buffer)?
you are passing attributes without initializing them.
To summarize, print errno and see what is wrong.