c - Processes synchronization with message queues and signals -
i have create 3 processes:
- reading expression 1+3+5+12
- checking if expression has correct syntax
- adding numbers , displaying them
data between processes shared using pipes mechanism. processes synchronization uses message queues , signals.i should able manually send signals each process through console.
the problem running processes seem run randomly. why that, what's wrong here? should work...
this whole code compiles correctly:
#include <stdio.h> #include <unistd.h> #include <signal.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <string.h> #include <stdlib.h> #include <stdbool.h> #define sizebuff 256 // signal handling each process void h_sig1(int signo); void h_sig2(int signo); void h_sig3(int signo); void h_s4(int signo); // processes functions void process1(void); void process2(void); void process3(void); // helper functions bool isinteger(double val); static pid_t p1, p2, p3; // pids each process int p; // parent pid int pfd12[2], pfd23[2]; // pipes between processes 1-2 , 2-3 int providepidy1[2], providepidy2[2]; // provide pids 1/2 process // message in message queue typedef struct { long type; int signum; } message; int queue_id; int main(void) { p = getpid(); // message queue created if ((queue_id = msgget(ipc_private,ipc_creat|0666)) < 0) { printf("msgget\n"); return 1; } if((p1 = fork()) == 0) { p1 = getpid(); process1(); } else if((p2 = fork()) == 0) { p2 = getpid(); process2(); } else if((p3 = fork()) == 0) { p3 = getpid(); process3(); } else { // sending signals parent through operator // sending pids process 1 close(providepidy1[0]); write(providepidy1[1], &p, sizeof(int)); write(providepidy1[1], &p1, sizeof(int)); write(providepidy1[1], &p2, sizeof(int)); write(providepidy1[1], &p3, sizeof(int)); close(providepidy1[1]); // sending pids process 2 close(providepidy2[0]); write(providepidy2[1], &p, sizeof(int)); write(providepidy2[1], &p1, sizeof(int)); write(providepidy2[1], &p2, sizeof(int)); write(providepidy2[1], &p3, sizeof(int)); close(providepidy2[1]); printf("\nprogram options:\n"); printf("send signal - 's'(send)\n"); printf("display processes pids 'p'(pids)\n"); printf("quit program - 'q'(quit)\n"); char choice, choice2, choice3; while(1) { choice = getchar(); if(choice == 's') { printf("which process receiving signal - 1, 2, or 3?: "); choice2 = getchar(); choice2 = getchar(); printf("\n"); if((choice2 < 1) && (choice2 > 3)) { printf("no such process!"); continue; } printf("what signal send?:\n"); printf("1-s1(end execution)\n2-s2(pause execution)\n3-s3(renew execution)?\n "); printf("choice: "); choice3 = getchar(); choice3 = getchar(); switch(choice2) { case '1': //nie można przechwycić sygnałów sigkill oraz sigstop (zabicia oraz zatrzymania) if(choice3 == '1') { kill(0,sigcont); kill(p1,sigusr1); } if(choice3 == '2') kill(p1,sigtstp); if(choice3 == '3') { kill(0,sigcont); kill(p3,sigalrm); } break; case '2': if(choice3 == '1') { kill(0,sigcont); kill(p2,sigusr1); } if(choice3 == '2') kill(p2,sigtstp); if(choice3 == '3') { kill(0,sigcont); kill(p3,sigalrm); } break; case '3': if(choice3 == '1') { kill(0,sigcont); kill(p3,sigusr1); } if(choice3 == '2') kill(p3,sigtstp); if(choice3 == '3') { kill(0,sigcont); kill(p3,sigalrm); } break; default: printf("no such operation!!! \n\n"); } } if(choice == 'p') { // } if(choice == 'q') { // } } } } void process1(void) { // receiving pids close(providepidy1[1]); read(providepidy1[0], &p, sizeof(int)); read(providepidy1[0], &p1, sizeof(int)); read(providepidy1[0], &p2, sizeof(int)); read(providepidy1[0], &p3, sizeof(int)); close(providepidy1[0]); struct sigaction act1; act1.sa_handler = h_sig1; sigemptyset(&act1.sa_mask); act1.sa_flags = 0; sigaction(sigusr1, &act1, 0); sigaction(sigtstp, &act1, 0); sigaction(sigalrm, &act1, 0); struct sigaction act; act.sa_handler = h_s4; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(sigint, &act, 0); // } void process2(void) { close(providepidy2[1]); read(providepidy2[0], &p, sizeof(int)); read(providepidy2[0], &p1, sizeof(int)); read(providepidy2[0], &p2, sizeof(int)); read(providepidy2[0], &p3, sizeof(int)); close(providepidy2[0]); struct sigaction act2; act2.sa_handler = h_sig2; sigemptyset(&act2.sa_mask); act2.sa_flags = 0; sigaction(sigusr1, &act2, 0); sigaction(sigtstp, &act2, 0); sigaction(sigalrm, &act2, 0); struct sigaction act; act.sa_handler = h_s4; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(sigint, &act, 0); // } void process3(void) { struct sigaction act3; act3.sa_handler = h_sig3; sigemptyset(&act3.sa_mask); act3.sa_flags = 0; sigaction(sigusr1, &act3, 0); sigaction(sigtstp, &act3, 0); sigaction(sigalrm, &act3, 0); struct sigaction act; act.sa_handler = h_s4; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(sigint, &act, 0); // } void h_sig1(int signo) { message msg; msg.type = p2; msg.signum = signo; kill(p2, sigint); // send type of receiving signal message queue msgsnd(queue_id, &msg, sizeof(msg.signum), 0); msg.type = p3; kill(p3, sigint); msgsnd(queue_id, &msg, sizeof(msg.signum), 0); if(signo == sigusr1) { } if(signo == sigtstp) { } if(signo == sigalrm) { } } void h_sig2(int signo) { message msg; msg.type = p1; msg.signum = signo; kill(p1, sigint); // send type of receiving signal message queue msgsnd(queue_id, &msg, sizeof(msg.signum), 0); msg.type = p3; kill(p3, sigint); msgsnd(queue_id, &msg, sizeof(msg.signum), 0); if(signo == sigusr1) { } if(signo == sigtstp) { } if(signo == sigalrm) { } } void h_sig3(int signo) { message msg; msg.type = p1; msg.signum = signo; kill(p1, sigint); // send type of receiving signal message queue msgsnd(queue_id, &msg, sizeof(msg.signum), 0); msg.type = p2; kill(p2, sigint); msgsnd(queue_id, &msg, sizeof(msg.signum), 0); if(signo == sigusr1) { } if(signo == sigtstp) { } if(signo == sigalrm) { } } void h_s4(int signo) { int res; message msg; printf("\nprocess pid=%d received signal s4", getpid()); if(signo == sigint) { res = msgrcv(queue_id, &msg, sizeof(msg.signum), msg.type, 0); if(res >= 0) { if(msg.signum == sigusr1) { } if(msg.signum == sigtstp) { } if(msg.signum == sigalrm) { } } } }
long version, compile:
#include <stdio.h> #include <unistd.h> #include <signal.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <string.h> #include <stdlib.h> #include <stdbool.h> #define sizebuff 200 // signal handling each process void h_sig1(int signo); void h_sig2(int signo); void h_sig3(int signo); void h_s4(int signo); // signal handling 4th signal // processes functions void process1(void); void process2(void); void process3(void); // helper functions bool isinteger(double val); static pid_t p1, p2, p3; // pids each process int p; // parent pid int pfd12[2], pfd23[2]; // pipes between processes 1-2 , 2-3 int providepidy1[2], providepidy2[2]; // provide pids 1/2 process // message in message queue typedef struct { long type; int signum; } message; int queue_id; int main(void) { p = getpid(); if (pipe(pfd12) == -1) { perror("pipe failed"); exit(1); } if (pipe(pfd23) == -1) { perror("pipe failed"); exit(1); } // message queue created if ((queue_id = msgget(ipc_private,ipc_creat|0666)) < 0) { printf("msgget\n"); return 1; } if (pipe(providepidy1) == -1) { perror("pipe failed"); exit(1); } if (pipe(providepidy2) == -1) { perror("pipe failed"); exit(1); } if((p1 = fork()) == 0) { p1 = getpid(); process1(); } else if(p1 < 0) { perror("fork failed"); exit(2); } else if((p2 = fork()) == 0) { p2 = getpid(); process2(); } else if(p2 < 0) { perror("fork failed"); exit(2); } else if((p3 = fork()) == 0) { p3 = getpid(); process3(); } else if(p3 < 0) { perror("fork failed"); exit(2); } else { // sending signals parent through operator // sending pids process 1 close(providepidy1[0]); write(providepidy1[1], &p, sizeof(int)); write(providepidy1[1], &p1, sizeof(int)); write(providepidy1[1], &p2, sizeof(int)); write(providepidy1[1], &p3, sizeof(int)); close(providepidy1[1]); // sending pids process 2 close(providepidy2[0]); write(providepidy2[1], &p, sizeof(int)); write(providepidy2[1], &p1, sizeof(int)); write(providepidy2[1], &p2, sizeof(int)); write(providepidy2[1], &p3, sizeof(int)); close(providepidy2[1]); printf("\nprogram options:\n"); printf("send signal - 's'(send)\n"); printf("display processes pids 'p'(pids)\n"); printf("quit program - 'q'(quit)\n"); char choice, choice2, choice3; while(1) { choice = getchar(); if(choice == 's') { printf("which process receiving signal - 1, 2, or 3?: "); choice2 = getchar(); choice2 = getchar(); printf("\n"); if((choice2 < 1) && (choice2 > 3)) { printf("no such process!"); continue; } printf("what signal send?:\n"); printf("1-s1(end execution)\n2-s2(pause execution)\n3-s3(renew execution)?\n "); printf("choice: "); choice3 = getchar(); choice3 = getchar(); switch(choice2) { case '1': //nie można przechwycić sygnałów sigkill oraz sigstop (zabicia oraz zatrzymania) if(choice3 == '1') { kill(0,sigcont); kill(p1,sigusr1); } if(choice3 == '2') kill(p1,sigtstp); if(choice3 == '3') { kill(0,sigcont); kill(p3,sigalrm); } break; case '2': if(choice3 == '1') { kill(0,sigcont); kill(p2,sigusr1); } if(choice3 == '2') kill(p2,sigtstp); if(choice3 == '3') { kill(0,sigcont); kill(p3,sigalrm); } break; case '3': if(choice3 == '1') { kill(0,sigcont); kill(p3,sigusr1); } if(choice3 == '2') kill(p3,sigtstp); if(choice3 == '3') { kill(0,sigcont); kill(p3,sigalrm); } break; default: printf("no such operation!!! \n\n"); } } if(choice == 'p') { printf("\n<processes pids:>\n"); printf("p(initial process)=%d\n",p); printf("p1(process 1)=%d\n",p1); printf("p2(process 2)=%d\n",p2); printf("p3(process 3)=%d\n\n",p3); } if(choice == 'q') { printf("\n<quitting program>\n"); msgctl(queue_id, ipc_rmid, 0); kill(0, sigkill); } } } } void process1(void) { int datasize; char buff[sizebuff]; // receiving pids close(providepidy1[1]); read(providepidy1[0], &p, sizeof(int)); read(providepidy1[0], &p1, sizeof(int)); read(providepidy1[0], &p2, sizeof(int)); read(providepidy1[0], &p3, sizeof(int)); close(providepidy1[0]); printf("\n<process 1 execution in progress>\n"); /*sigaction*/ struct sigaction act1; act1.sa_handler = h_sig1; sigemptyset(&act1.sa_mask); act1.sa_flags = 0; sigaction(sigusr1, &act1, 0); sigaction(sigtstp, &act1, 0); sigaction(sigalrm, &act1, 0); struct sigaction act; act.sa_handler = h_s4; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(sigint, &act, 0); close(pfd12[0]); while(1) { printf("provide expr: "); scanf("%s", buff); if(strcmp(buff, "0") == 0) break; datasize = strlen(buff) + 1; // plus null if(datasize > 0) write(pfd12[1], &datasize, sizeof(int)); write(pfd12[1], &buff, sizeof(char)*datasize); } datasize = 0; // info there's no more data write(pfd12[1], &datasize, sizeof(int)); close(pfd12[1]); printf("\n---process 1 finished execution---\n"); exit(0); } void process2(void) { int datasize; char buff[sizebuff]; char *token, *end; int number; const char delim[2] = "+"; //odebranie pidow close(providepidy2[1]); read(providepidy2[0], &p, sizeof(int)); read(providepidy2[0], &p1, sizeof(int)); read(providepidy2[0], &p2, sizeof(int)); read(providepidy2[0], &p3, sizeof(int)); close(providepidy2[0]); printf("\n<process 2 execution in progress>\n"); /*sigaction*/ struct sigaction act2; act2.sa_handler = h_sig2; sigemptyset(&act2.sa_mask); act2.sa_flags = 0; sigaction(sigusr1, &act2, 0); sigaction(sigtstp, &act2, 0); sigaction(sigalrm, &act2, 0); struct sigaction act; act.sa_handler = h_s4; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(sigint, &act, 0); close(pfd12[1]); read(pfd12[0], &datasize, sizeof(int)); if(datasize > 0) { sleep(3); read(pfd12[0], buff, datasize); token = strtok(buff, delim); while( token != null ) { number = strtol(token, &end, 0); if(!isinteger(number)) break; } } close(pfd12[0]); // sending result process 3 close(pfd23[0]); write(pfd23[1], &buff, sizeof(int)); close(pfd23[1]); printf("\n---process 2 finished execution---\n"); } void process3(void) { int sum = 0; char buff[sizebuff]; char* token, *end; int number; const char delim[2] = "+"; /*sigaction*/ struct sigaction act3; act3.sa_handler = h_sig3; sigemptyset(&act3.sa_mask); act3.sa_flags = 0; sigaction(sigusr1, &act3, 0); sigaction(sigtstp, &act3, 0); sigaction(sigalrm, &act3, 0); struct sigaction act; act.sa_handler = h_s4; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(sigint, &act, 0); printf("\n<process 3 execution in progress>"); close(pfd23[1]); read(pfd23[0], &buff, sizeof(int)); token = strtok(buff, delim); while( token != null ) { number = strtol(token, &end, 0); sum += number; } printf("sum = %d\n", sum); close(pfd23[0]); printf("\n---process 3 finished execution ---\n"); printf("\n---program finished execution---\n"); kill(getppid(),sigkill); } /*******************************************************************************************************/ /****************************************signal handling (s1-s3)***********************************************/ /*******************************************************************************************************/ void h_sig1(int signo) { message msg; msg.type = p2; msg.signum = signo; kill(p2, sigint); // send type of receiving signal message queue msgsnd(queue_id, &msg, sizeof(msg.signum), 0); msg.type = p3; kill(p3, sigint); msgsnd(queue_id, &msg, sizeof(msg.signum), 0); if(signo == sigusr1) { printf("\nprocess 1 received signal s1\n"); printf("terminating parent process!\n"); kill(getppid(), sigkill); printf("terminating process 1!\n"); kill(getpid(), sigkill); } if(signo == sigtstp) { printf("\nprocess 1 received signal s2\n"); printf("pausing process 1!\n"); kill(getpid(), sigstop); } if(signo == sigalrm) { printf("\nprocess 1 received signal s3\n"); printf("renewing execution of process 1!\n"); kill(getpid(), sigcont); } } void h_sig2(int signo) { message msg; msg.type = p1; msg.signum = signo; kill(p1, sigint); // send type of receiving signal message queue msgsnd(queue_id, &msg, sizeof(msg.signum), 0); msg.type = p3; kill(p3, sigint); msgsnd(queue_id, &msg, sizeof(msg.signum), 0); if(signo == sigusr1) { printf("\nprocess 2 received signal s1\n"); printf("terminating parent process!\n"); kill(getppid(), sigkill); printf("terminating process 2!\n"); kill(getpid(), sigkill); } if(signo == sigtstp) { printf("\nprocess 2 received signal s2\n"); printf("pausing process 2!\n"); kill(getpid(), sigstop); } if(signo == sigalrm) { printf("\nprocess 2 received signal s3\n"); printf("renewing execution of process 2!\n"); kill(getpid(), sigcont); } } void h_sig3(int signo) { message msg; msg.type = p1; msg.signum = signo; kill(p1, sigint); // send type of receiving signal message queue msgsnd(queue_id, &msg, sizeof(msg.signum), 0); msg.type = p2; kill(p2, sigint); msgsnd(queue_id, &msg, sizeof(msg.signum), 0); if(signo == sigusr1) { printf("\nprocess 3 received signal s1\n"); printf("terminating parent process!\n"); kill(getppid(), sigkill); printf("terminating process 3!\n"); kill(getpid(), sigkill); } if(signo == sigtstp) { printf("\nprocess 3 received signal s2\n"); printf("pausing process 3!\n"); kill(getpid(), sigstop); } if(signo == sigalrm) { printf("\nprocess 3 received signal s3\n"); printf("renewing execution of process 3!\n"); kill(getpid(), sigcont); } } /*******************************************************************************************************/ /****************************************handling s4 signal***********************************/ /*******************************************************************************************************/ void h_s4(int signo) { int res; message msg; printf("\nprocess pid=%d received signal s4", getpid()); if(signo == sigint) { res = msgrcv(queue_id, &msg, sizeof(msg.signum), msg.type, 0); if(res >= 0) { if(msg.signum == sigusr1) { printf("terminating process\n"); kill(getpid(),sigkill); } if(msg.signum == sigtstp) { printf("pausing process\n"); kill(getpid(),sigstop); } if(msg.signum == sigalrm) { printf("renewing process\n"); kill(getpid(),sigcont); } } } } bool isinteger(double val) { int truncated = (int)val; return (val == truncated); }
source code analysis
there consistency problems:
static pid_t p1, p2, p3; // pids each process int p; // parent pid
why p
, int
instead of pid_t
? why global instead of static
? why p
instead of p0
? should whole lot array?
static pid_t p[4];
(there benefits using array!)
there repetition should in function invoked multiple times:
// sending pids process 1 close(providepidy1[0]); write(providepidy1[1], &p, sizeof(int)); write(providepidy1[1], &p1, sizeof(int)); write(providepidy1[1], &p2, sizeof(int)); write(providepidy1[1], &p3, sizeof(int)); close(providepidy1[1]); // sending pids process 2 close(providepidy2[0]); write(providepidy2[1], &p, sizeof(int)); write(providepidy2[1], &p1, sizeof(int)); write(providepidy2[1], &p2, sizeof(int)); write(providepidy2[1], &p3, sizeof(int)); close(providepidy2[1]);
note there's repetition because p
values aren't array. there's possible portability liability; pid_t
not have same size int
.
there problems checking inputs:
choice = getchar(); if(choice == 's')
since choice
char
, can erroneous handling of eof — if bothered test it. leave newline (at least) in input, , don't skip leading spaces in input. you'd better reading line of data (fgets()
or posix readline()
) , using if (sscanf(buffer, " %c", &choice) != 1) { …handle error… }
character.
your next input block curious:
printf("which process receiving signal - 1, 2, or 3?: "); choice2 = getchar(); choice2 = getchar(); printf("\n"); if((choice2 < 1) && (choice2 > 3))
the first input reads newline (assuming there no trailing spaces, etc), , second gets '1'
, '2'
, or '3'
. however, test whether input value both less 1 , greater 3, , there's no known value in universe both conditions true (nan
values unknown values). wanted like:
if (choice2 < '1' || choice2 > '3')
after you've determined signal send (more or less), have block of repeated code because used p1
etc instead of array p
.
there chunks of repeated code in child processes, such code reads process numbers. these should in function, too. signal handling setup should in function too, though i've not spent lot of time checking differences , similarities between different process functions.
major problem
you code supposed processing arithmetic expressions. have main program loop reading choices signal handling, seem have process1()
trying read expressions. bad news; indeterminate of processes read given input.
back small stuff
you have:
datasize = strlen(buff) + 1; // plus null if(datasize > 0) write(pfd12[1], &datasize, sizeof(int)); write(pfd12[1], &buff, sizeof(char)*datasize);
the test little pointless; minimum value strlen()
can return 0
, minimum value in datasize
1
, condition true. (theoretically, suppose, enter data size_t
returned strlen()
overflows int datasize
, you've not allocated enough space actual problem — code have had other problems before that.)
in process2()
, code curious:
token = strtok(buff, delim); while( token != null ) { number = strtol(token, &end, 0); if(!isinteger(number)) break; }
there no circumstances under int number;
going non-integer when scan string strtol()
. have risk of overflow (sizeof(int) != sizeof(long)
on 64-bit unix systems, example). have risk of not being able interpret remnants of floating point value (because .
not valid part of integer). you'll need rework code.
there's lot of repetition in signal handling code; should refactored need fewer functions. it'll easier understand in long run. copy'n'paste'n'edit bad way of programming when result near clones of code in single program.
i'm not clear differences between 2 versions show; i've not scrutinized them. should @ how create mcve (how create minimal, complete, , verifiable example?) or sscce (short, self-contained, correct example) — 2 names , links same basic idea. i'm not sure either lot of code qualifies mcve; both versions overkill. supply compilable code.
after compilation
i've compiled second chunk of code (saved in file called procsync.c
) on mac running mac os x 10.10.3 gcc 5.1.0, , using command line:
$ gcc -o3 -g -std=c11 -wall -wextra -wmissing-prototypes -wstrict-prototypes \ > -wold-style-definition -werror procsync.c -o procsync $
to considerable surprise, code compiled under stringent options no complaints — seldom see in code on so.
congratulations!
(but there still other issues worry about.)
Comments
Post a Comment