Implementation of Bakery Algorithm in C for forked processes - c
So, I'm new to shared memory and the shm functions in C.
I've got two programs; master and slave. In the most general sense: the master program creates a sharedNum integer in shared memory and forks off multiple processes that exec the slave program. The slave program processes must then increment sharedNum from shared memory (perhaps multiple times, even) and print it to a specified file. I am 100% confident that everything is working (though it may look messy) aside from the shared memory manipulation. I've been testing throughout development.
The problem I'm having is with race conditions in the slave program processes. I understand that I need to implement the Bakery algorithm in order to lock and unlock processes from accessing the critical section. The lack of this causes sharedNum manipulation to be off.
I attempted to implement a form of the Bakery algorithm in my slave program, but it doesn't seem to work... Through testing, I've discovered that the choosing and turnNum variables (which I NEED to use for the Bakery algorithm, as far as I understand) are themselves experiencing race conditions. How is this avoidable? I'm pretty sure they need to be in shared memory as well, otherwise they couldn't be updated by multiple processes...
Thanks in advance.
Program dumps follow.
master.c:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<ctype.h>
#include<string.h>
#include<errno.h>
#include<signal.h>
#include<sys/ipc.h>
#include<sys/shm.h>
// global variables
pid_t *children;
int slave_max;
// globals relating to shared memory
key_t shmkey;
int shmid_sharedNum;
int *sharedNum;
void handle_sigalrm(int signum, siginfo_t *info, void *ptr)
{
// prevents multiple interrupts
signal(SIGINT, SIG_IGN);
fprintf(stderr, "Master ran out of time\n");
// detaching and deleting shared memory
shmdt(sharedNum);
shmctl(shmid_sharedNum, IPC_RMID, NULL);
// creating tmp_children to replace children
// this way children can be freed before SIGTERM
pid_t tmp_children[slave_max];
int i;
for (i = 0; i < slave_max; i++);
{
tmp_children[i] = children[i];
}
// freeing allocated memory
free(children);
// terminate child processes
for (i = 0; i < slave_max; i++)
{
kill(tmp_children[i], SIGTERM);
}
}
void handle_sigint(int signum, siginfo_t *info, void *ptr)
{
// prevents multiple interrupts
signal(SIGINT, SIG_IGN);
signal(SIGALRM, SIG_IGN);
fprintf(stderr, " interrupt was caught by master\n");
// detaching and deleting shared memory
shmdt(sharedNum);
shmctl(shmid_sharedNum, IPC_RMID, NULL);
// creating tmp_children to replace children
// this way children can be freed before SIGTERM
pid_t tmp_children[slave_max];
int i;
for (i = 0; i < slave_max; i++)
{
tmp_children[i] = children[i];
}
// freeing allocated memory
free(children);
// terminate child processes
for (i = 0; i < slave_max; i++)
{
kill(tmp_children[i], SIGTERM);
}
}
void catch_sigalrm()
{
static struct sigaction _sigact;
memset(&_sigact, 0, sizeof(_sigact));
_sigact.sa_sigaction = handle_sigalrm;
_sigact.sa_flags = SA_SIGINFO;
sigaction(SIGALRM, &_sigact, NULL);
}
void catch_sigint()
{
static struct sigaction _sigact;
memset(&_sigact, 0, sizeof(_sigact));
_sigact.sa_sigaction = handle_sigint;
_sigact.sa_flags = SA_SIGINFO;
sigaction(SIGINT, &_sigact, NULL);
}
int main(int argc, char *argv[])
{
// default variables
int i = 0; // to be used as a counter variable
slave_max = 5;
char slave_max_str[25]; // arbitrary size
char *log_filename = NULL;
int slave_increment = 3;
char slave_increment_str[25]; // arbitrary size
int master_time = 20;
// shared memory initialization
shmkey = ftok("./master", 118371); // arbitrary key
shmid_sharedNum = shmget(shmkey, sizeof(sharedNum), 0600 | IPC_CREAT);
sharedNum = (int *)shmat(shmid_sharedNum, NULL, 0);
sharedNum[0] = 0;
// handling command line args with getopt
int c;
while((c = getopt(argc, argv, "hs:l:i:t:")) != -1)
{
switch(c)
{
// -h : program help
case 'h':
// the following if-else block makes sure
// that -h will be used by itself
if (argc == 2)
{
printf("%s -h : program help\n", argv[0]);
printf("%s -s [integer] : set max number of slave processes\n", argv[0]);
printf("%s -l [filename] : set log filename\n", argv[0]);
printf("%s -i [integer] : set slave process incrementer\n", argv[0]);
printf("%s -t [integer] : set number of seconds master will terminate\n", argv[0]);
exit(0);
}
else
{
fprintf(stderr, "%s: option must be used by itself -- 'h'\n", argv[0]);
exit(1);
}
// -s [integer] : set max number of slave processes
case 's':
slave_max = atoi(optarg);
break;
// -l [filename] : set log filename
case 'l':
log_filename = optarg;
break;
// -i [integer] : set slave process incrementer
case 'i':
slave_increment = atoi(optarg);
break;
// -t [integer] : set number of seconds master will terminate
case 't':
master_time = atoi(optarg);
break;
// the following case takes care of user input errors
case '?':
if (optopt == 's')
fprintf(stderr, "Error: -s requires an integer\n");
else if (optopt == 'l')
fprintf(stderr, "Error: -l requires a filename\n");
else if (optopt == 'i')
fprintf(stderr, "Error: -i requires an integer\n");
else if (optopt == 't')
fprintf(stderr, "Error: -t requires an integer\n");
else if (isprint(optopt))
fprintf(stderr, "Error: input can't be printed\n");
else
fprintf(stderr, "Error: invalid syntax\n");
exit(1);
default:
abort();
}
}
catch_sigint();
catch_sigalrm();
alarm(master_time);
// if log_filename wasn't passed in by -l,
// its default value is set here...
if (!log_filename)
log_filename = "test.out";
// setting slave_increment_str and slave_max_str
// for use in future execl
snprintf(slave_increment_str, 25, "%i", slave_increment);
snprintf(slave_max_str, 25, "%i", slave_max);
// initializing pids
if ((children = (pid_t *)(malloc(slave_max * sizeof(pid_t)))) == NULL)
{
errno = ENOMEM;
perror("children malloc");
exit(1);
}
pid_t p;
// forking off child processes
for (i = 0; i < slave_max; i++)
{
p = fork();
if (p < 0)
{
fprintf(stderr,"Error: fork failed\n");
continue;
}
if (p == 0)
{
children[i] = p;
execl("./slave", "slave", "-l", log_filename, "-s", slave_max_str, "-i", slave_increment_str, (char *) NULL);
exit(0);
}
}
// waiting for all child processes to finish
for (i = 0; i < slave_max; i++)
{
int status;
waitpid(children[i], &status, 0);
}
// clean up and finish
free(children);
shmdt(sharedNum);
shmctl(shmid_sharedNum, IPC_RMID, NULL);
return 0;
}
slave.c:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<ctype.h>
#include<sys/types.h>
#include<time.h>
#include<signal.h>
#include<sys/ipc.h>
#include<sys/shm.h>
// global variables
pid_t parent;
pid_t child;
int childProc;
// globals for shared memory
key_t shmkey;
int shmid_sharedNum, shmid_choosing, shmid_turnNum;
int *sharedNum; int *choosing; int *turnNum;
void handle_sigterm(int signum, siginfo_t *info, void *ptr)
{
// detaching and deleting shared memory
shmdt(sharedNum);
shmdt(choosing);
shmdt(turnNum);
shmctl(shmid_sharedNum, IPC_RMID, NULL);
shmctl(shmid_choosing, IPC_RMID, NULL);
shmctl(shmid_turnNum, IPC_RMID, NULL);
fprintf(stderr, "Process #%i was terminated by master\n", childProc);
exit(0);
}
void catch_sigterm()
{
static struct sigaction _sigact;
memset(&_sigact, 0, sizeof(_sigact));
_sigact.sa_sigaction = handle_sigterm;
_sigact.sa_flags = SA_SIGINFO;
sigaction(SIGTERM, &_sigact, NULL);
}
int main(int argc, char *argv[])
{
// default variables
parent = getppid();
child = getpid();
childProc = (int)(child - parent);
int i, j, maxCounter; // to be used as a counter variables
int slave_max = 1;
char *log_filename = NULL;
int slave_incrementer = 3;
srand(time(NULL));
int napTime;
// shared memory initialization
shmkey = ftok("./master", 118371); // arbitrary key
shmid_sharedNum = shmget(shmkey, sizeof(sharedNum), 0600 | IPC_CREAT);
sharedNum = (int *)shmat(shmid_sharedNum, NULL, 0);
shmid_choosing = shmget(shmkey, sizeof(choosing), 0600 | IPC_CREAT);
choosing = (int *)shmat(shmid_choosing, NULL, 0);
shmid_turnNum = shmget(shmkey, sizeof(turnNum), 0600 | IPC_CREAT);
turnNum = (int *)shmat(shmid_turnNum, NULL, 0);
catch_sigterm();
signal(SIGINT, SIG_IGN);
// implementing getopt to handle command line args
int c;
while((c = getopt(argc, argv, "s:l:i:")) != -1)
{
switch(c)
{
// -s [integer] : number of slave processes
case 's':
slave_max = atoi(optarg);
// -l [filename] : set log filename
case 'l':
log_filename = optarg;
break;
// -i [integer] : set slave process incrementer
case 'i':
slave_incrementer = atoi(optarg);
break;
// this case takes care of user input errors
case '?':
if (optopt == 's')
fprintf(stderr, "Error: -s requires an integer\n");
else if (optopt == 'l')
fprintf(stderr, "Error: -l requires a filename\n");
else if (optopt == 'i')
fprintf(stderr, "Error: -i requires an integer\n");
else if (isprint(optopt))
fprintf(stderr, "Error: input can't be printed\n");
else
fprintf(stderr, "Error: invalid syntax\n");
exit(1);
default:
abort();
}
}
// if log_filename wasn't passed in by -l,
// its default value is set here...
if (!log_filename)
log_filename = "test.out";
struct timespec now;
long curTime;
int max = 0;
for (i = 0; i < slave_incrementer; i++)
{
// execute code to enter critical section
choosing[(childProc-1)] = 1;
for (maxCounter = 0; maxCounter < slave_max; maxCounter++)
{
if((turnNum[maxCounter]) > max)
max = (turnNum[maxCounter]);
}
turnNum[(childProc-1)] = 1 + max;
printf("turnNum for process #%i = %i\n", childProc, turnNum[(childProc-1)]);
choosing[(childProc-1)] = 0;
for (j = 0; j < slave_max; j++)
{
while (choosing[j] == 1) {}
while ((turnNum[j] != 0) && (turnNum[j] < turnNum[(childProc-1)])) {}
}
// critical section
napTime = rand() % 3;
sleep(napTime);
sharedNum[0]++;
clock_gettime(CLOCK_REALTIME, &now);
curTime = ((((long)now.tv_sec) * 1000000000) + (long)now.tv_nsec);
// write message to log file here
// for testing purposes:
printf("File modified by process #%i (increment %i) at time %ld with sharedNum = %i\n", childProc, (i+1), curTime, sharedNum[0]);
napTime = rand() % 3;
sleep(napTime);
// exit from critical section
turnNum[(childProc-1)] = 0;
}
// clean up and finish
shmdt(sharedNum);
shmdt(choosing);
shmdt(turnNum);
shmctl(shmid_sharedNum, IPC_RMID, NULL);
shmctl(shmid_choosing, IPC_RMID, NULL);
shmctl(shmid_turnNum, IPC_RMID, NULL);
return 0;
}
(Broken) Bakery algorithm section of slave.c:
// execute code to enter critical section
choosing[(childProc-1)] = 1;
for (maxCounter = 0; maxCounter < slave_max; maxCounter++)
{
if((turnNum[maxCounter]) > max)
max = (turnNum[maxCounter]);
}
turnNum[(childProc-1)] = 1 + max;
printf("turnNum for process #%i = %i\n", childProc, turnNum[(childProc-1)]);
choosing[(childProc-1)] = 0;
for (j = 0; j < slave_max; j++)
{
while (choosing[j] == 1) {}
while ((turnNum[j] != 0) && (turnNum[j] < turnNum[(childProc-1)])) {}
}
// critical section
napTime = rand() % 3;
sleep(napTime);
sharedNum[0]++;
clock_gettime(CLOCK_REALTIME, &now);
curTime = ((((long)now.tv_sec) * 1000000000) + (long)now.tv_nsec);
// write message to log file here
// for testing purposes:
printf("File modified by process #%i (increment %i) at time %ld with sharedNum = %i\n", childProc, (i+1), curTime, sharedNum[0]);
napTime = rand() % 3;
sleep(napTime);
// exit from critical section
turnNum[(childProc-1)] = 0;
I discovered this a while ago, but forgot to provide the solution. It turns out that my implementation of the Bakery algorithm was fine. The real issue came from how I was initializing my shared memory segments in slave.c. By using different keys for each segment, I was able to run my master program with expected results.
updated "shared memory initialization" section of slave.c:
// shared memory initialization
shmkey = ftok("./master", 118371); // arbitrary key #1
shmid_sharedNum = shmget(shmkey, sizeof(sharedNum), 0600 | IPC_CREAT);
sharedNum = (int *)shmat(shmid_sharedNum, NULL, 0);
shmkey = ftok("./slave", 118372); // arbitrary key #2
shmid_choosing = shmget(shmkey, sizeof(choosing), 0600 | IPC_CREAT);
choosing = (int *)shmat(shmid_choosing, NULL, 0);
shmkey = ftok("./slave", 118373); // arbitrary key #3
shmid_turnNum = shmget(shmkey, sizeof(turnNum), 0600 | IPC_CREAT);
turnNum = (int *)shmat(shmid_turnNum, NULL, 0);
Related
How to create a shared buffer of a value from the command line in C (producer/consumer multi-threading problem)?
I get the size of a buffer to be created from the command line with this code: while ((c = getopt(argc, argv, "d:p:t:b:")) != -1) switch (c) { case 'd': root_dir = optarg; break; case 'p': port = atoi(optarg); break; case 't': // NUMBER OF CONSUMER THREADS n_threads = atoi(optarg); break; case 'b': // BUFFER SIZE THREAD_BUFFER_SIZE = atoi(optarg); default: fprintf(stderr, "usage: wserver [-d basedir] [-p port] [-t threads] [-b buffer] \n"); exit(1); } Which is contained in my main() function. Lets say I execute ./wserver -d . -p 8004 -t 8 -b 10. I expect to get a buffer of size 10. This buffer is being shared between producer and consumer threads, whose function implementations lie outside of the main() function. With that, I receive an error stating 'buffer is undeclared.' I then created a buffer of default size, lets say 4 (int buffer[4];), outside of the main function so that it would be declared. Then inside of the main() function, I add buffer = buffer[THREAD_BUFFER_SIZE], which gets the size requested from the getopt case statement above. Which is obviously wrong, but I do not understand how to replace this code to allow the shared buffer of a size requested to be created. Any tips? Default initialized buffer on line 3 and shared buffer commented: char default_root[] = "."; int count = 0; int buffer[10]; void *producer(void *THREAD_BUFFER_SIZE) { [uses buffer] } void *consumer(void *arg) { [uses buffer] } int main(int argc, char *argv[]) { int c; char *root_dir = default_root; int port = 10000; // I created these int n_threads; int THREAD_BUFFER_SIZE; pthread_t* mythreads; // consumer threads pthread_t p_id; // producer thread while ((c = getopt(argc, argv, "d:p:t:b:")) != -1) switch (c) { case 'd': root_dir = optarg; break; case 'p': port = atoi(optarg); break; case 't': // NUMBER OF CONSUMER THREADS n_threads = atoi(optarg); break; case 'b': // BUFFER SIZE THREAD_BUFFER_SIZE = atoi(optarg); default: fprintf(stderr, "usage: wserver [-d basedir] [-p port]\n"); exit(1); } // SHARED BUFFER buffer = buffer[THREAD_BUFFER_SIZE]; // Create producer thread if (pthread_create(&p_id, NULL, producer, (void*) THREAD_BUFFER_SIZE) != 0) { fprintf(stderr, "unable to create producer thread\n"); exit(1); } // Create n_threads consumer threads mythreads = (pthread_t*) malloc(sizeof(pthread_t)*n_threads); for(int i = 0; i < n_threads; i++) { if(pthread_create(&mythreads[i], NULL, consumer, NULL) != 0) { fprintf(stderr, "unable to create consumer thread\n"); exit(1); } } // run out of this directory chdir_or_die(root_dir); // now, get to work int listen_fd = open_listen_fd_or_die(port); while (1) { struct sockaddr_in client_addr; int client_len = sizeof(client_addr); int conn_fd = accept_or_die(listen_fd, (sockaddr_t *) &client_addr, (socklen_t *) &client_len); request_handle(conn_fd); close_or_die(conn_fd); } // Added at end to close and clean pthread_join(p_id, NULL); free(mythreads); pthread_mutex_destroy(&mut); return 0; }
C programm with wait(NULL) doesnt end like it should
I have written this code which is supposed to make N producers (P) and a consumer (C). Those two exchange K messages which are in two separate shared memory segments (sms). P's send to C a line and their pid. C sends back this line capitalized with the pid of the P that sent it. When K messages have been sent C must calculate and print how many times P's have read their own message capitalized. I put a wait(NULL) in the end so that C waits for all P's to put their personal pid_match in a buffer of a 3rd sms so it can read the right values after. Instead when i execute the code it only reads the pid_match from the 1st P and then terminates. Why does that happen. I post the code below. If any examples of execution are usefull i can provide them. #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sem.h> #include <string.h> #include <ctype.h> #include <time.h> #include "myheader.h" int main (int argc , char* argv[]){ if(argc<3) { printf("Programm needs more arguments (K and N) \n"); return(-1); } else { const int SHMSIZE = sizeof(struct message); // Shared Memory size = the size of a message int K, N, k, n, child_pid, shmid_in, shmid_out, shmid_pid, full_in, empty_in, full_out, empty_out, empty_pid, full_pid, pid_match=0,status,G; key_t shmkey_in, shmkey_out, semkey0_in, semkey1_in, semkey0_out, semkey1_out; struct message *shm_in, *shm_out; int *shm_pid; //struct sembuf oparray[1]={0,1,0}; K=atoi(argv[1]); N=atoi(argv[2]); const int shm_pidsize = N*sizeof(int); if(K==0 || N==0) return 0; //if no producers exist the programm should exit printf("%d %d \n", K, N ); /* --- Keys Initialization --- */ shmkey_in = ftok("/OS1.c", 1); shmkey_out = ftok("/OS1.c", 2); semkey0_in = ftok("/OS1.c", 3); // full_in semkey semkey1_in = ftok("/OS1.c", 4); // empty_in semkey Tou P oi 2 gia to sms in (apo P se C dld) semkey0_out = ftok("/OS1.c", 5); // full_out semkey semkey1_out = ftok("OS1.c", 6); // empty_out semkey Tou P oi 2 gia to sms out (apo C se P dld) /* --- Shared memory creation --- */ shmid_in = shmget(IPC_PRIVATE,SHMSIZE, IPC_CREAT | 0666); shmid_out = shmget(IPC_PRIVATE,SHMSIZE, IPC_CREAT | 0666); shmid_pid = shmget(IPC_PRIVATE,shm_pidsize,IPC_CREAT | 0666); // shm_pid creation shm_in = (struct message*)shmat(shmid_in,NULL,0); shm_out = (struct message*)shmat(shmid_out,NULL,0); shm_pid = (int*)shmat(shmid_pid,NULL,0); // shm_pid attach /* --- Semaphore creation --- */ full_in = semget(IPC_PRIVATE,1,IPC_CREAT | 0666); empty_in = semget(IPC_PRIVATE,1,IPC_CREAT | 0666); full_out = semget(IPC_PRIVATE,1,IPC_CREAT | 0666); empty_out = semget(IPC_PRIVATE,1,IPC_CREAT | 0666); full_pid = semget(IPC_PRIVATE,1,IPC_CREAT | 0666); empty_pid = semget(IPC_PRIVATE,1,IPC_CREAT | 0666); /* --- Semaphore Initialization --- */ union semum init0,init1; init0.val=0; init1.val=1; semctl(full_in,0,SETVAL,init0); // full_in = 0 semctl(empty_in,0,SETVAL,init1); // empty_in = 1 semctl(full_out,0,SETVAL,init0); // full_out = 0 semctl(empty_out,0,SETVAL,init1); // emty_out = 1 semctl(full_pid,0,SETVAL,init0); // pid_full = 0 semctl(empty_pid,0,SETVAL,init1); // pid_empty = 1 /* --- Semaphore oparations buffers --- */ struct sembuf full_in_up = {0,1,0}; struct sembuf full_in_down = {0,-1,0}; struct sembuf empty_in_up = {0,1,0}; // Operations of P to semaphores 0,1,2 struct sembuf empty_in_down = {0,-1,0}; struct sembuf full_out_up = {0,1,0}; struct sembuf full_out_down = {0,-1,0}; struct sembuf empty_out_up = {0,1,0}; // Operations of C to semaphores 0,1,2 struct sembuf empty_out_down = {0,-1,0}; struct sembuf full_pid_up = {0,1,0}; struct sembuf full_pid_down = {0,-1,0}; struct sembuf empty_pid_up = {0,1,0}; struct sembuf empty_pid_down = {0,-1,0}; for(n=0; n<N; n++) { child_pid = fork(); //printf("child_pid = fork();\n "); if (child_pid == 0) { printf(" --- this is %d th child with pid: %d---\n \n", n, getpid()); int pid_match = 0; // Initialize pid_match while(1){ //printf("int pid_match = 0; // Initialize pid_match\n while(1){\n"); // printf("%d \n",semctl(empty_in,0,GETVAL)); // sleep(1); semop(empty_in, &empty_in_down,1); // down(empty_in) // printf("%d \n",semctl(empty_in,0,GETVAL)); //printf(" down(empty_in)\n"); struct message msg; msg.pid = getpid(); char buf[max_line_length]; FILE *ptr_file; ptr_file =fopen("input.txt","r"); if (!ptr_file) perror("File failed to open"); long curtime = time(NULL); srand((unsigned int) curtime); sleep(1); // produce & send int i=1, j=0, luckyline = rand() % 5 + 1; //printf("%d\n", luckyline); while (fgets(buf, 1000, ptr_file)!=NULL && i<5) { if (i == luckyline) { //printf("%s \n",buf); strcpy(msg.line,buf); // complete the message strcpy(shm_in->line,msg.line); // send message to sms shm_in->pid = getpid(); //printf("pid = %d\n",shm_in->pid ); break; } i++; } fclose(ptr_file); // strcpy(shm_in->line, "message"); // printf("message copy\n"); // shm_in->pid = child_pid; semop(full_in,&full_in_up,1); // up full //printf("shared memory in full \n"); // read from C and kill if K messages have been sent semop(full_out,&full_out_down,1); // down full //if (strcmp(shm_out->line,"kill")!=0) printf("%s\n", shm_out->line); if (strcmp(shm_out->line,"kill") == 0) { semop(empty_pid,&empty_pid_down,1); shm_pid[j]=pid_match; j++; semop(full_pid,&full_pid_up,1); printf("%d pid_match = %d\n",getpid(),pid_match ); printf("kill\n"); exit(1); } if (shm_out->pid == getpid()) { //strcpy(shm_out->line,"\0"); shm_out->pid = 0; printf("Pid's match\n"); pid_match++; } semop(empty_out,&empty_out_up,1); // empty up } //sleep(20); }else if(child_pid < 0){ perror("fork failed\n"); }else { // break; } } for (k=0; k<K; k++) { int j=0; struct message m_out; //printf("Consumer running\n"); semop(full_in,&full_in_down,1); //down full _in //sleep(1); //printf("Full got 'downed'\n"); m_out.pid = shm_in->pid; while (shm_in->line[j] != '\0') { m_out.line[j] = toupper(shm_in->line[j]); // write in m_out->line the content of shm_in->line capitalized j++; } /*if (k == K) { printf("kill\n"); strcpy(shm_out->line, "kill"); }*/ semop(empty_in,&empty_in_up,1); //up empty_in semop(empty_out,&empty_out_down,1); // down empty_out //printf("shm_in->line = %s \n", shm_in->line ); // m_out->line = shm_in->line; // capitalize & send //strcpy(shm_out->line,m_out.line); //shm_out->pid = m_out.pid; printf("shm_in->line = %s \n", shm_in->line ); strcpy(shm_out->line,m_out.line); printf("shm_out->line = %s\n", shm_out->line); shm_out->pid = m_out.pid; semop(full_out,&full_out_up,1); //up full } if (k == K) { printf("C kill\n"); semop(empty_out,&empty_out_down,1); strcpy(shm_out->line, "kill"); semop(full_out,&full_out_up,1); } wait(NULL); //sleep(2); //printf("pid_match = %s\n",pid_match); for(G=0; G<N; G++){ //sleep(2); pid_match += shm_pid[G]; //printf("(pid_match = %s\n",pid_match); if(G == N-1) printf("Completed execution, exit %d\n",pid_match ); } /* --- TERM ---*/ semctl(full_out,0,IPC_RMID,0); semctl(full_in,0,IPC_RMID,0); semctl(empty_out,IPC_RMID,0); semctl(empty_in,0,IPC_RMID,0); semctl(full_pid,0,IPC_RMID,0); semctl(empty_pid,0,IPC_RMID,0); shmdt(shm_pid); shmdt(shm_in); shmdt(shm_out); } return 0; }
The wait function with a NULL argument only waits for one child process to exit. Then it stops waiting. You need to wait for all processes to exit. You can do that by saving all child-process pids, and then wait in a loop until they have all exited (checking using the return value of wait).
mqueue receive wrong data
Below is the code for an assignment on processor farming. The focus is on the comments with "HERE $resp is always the same/different". That's my problem: when the worker process does it's job and sends the response data to the farmer, the farmer always receives the same response data (the same pointer address), even though worker sends different data every time. Example: workers send data at addresses: 0x7fff42318a90,0x7ffddba97390,0x7ffc69e8e060 etc. and farmer keeps receiving data from only one address 0x7ffdb1496f30 I've done my best to abstract the code and question as much as possible. If I've omitted important information please let me know, I'm new to process management programming and I could use some guidance. UPDATE: also printing the contents of resp s.a resp.b where b is an integer returns the same value, even though the value is different in worker. UPDATE: I tried writing some runnable code only this time the worker might not be receiving. //both in farmer and in worker #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <unistd.h> // for execlp #include <mqueue.h> // for mq typedef struct{ int a; } REQUEST; typedef struct{ int b; } RESPONSE; static char mq_farmer[80]; static char mq_worker[80]; //farmer: int main (int argc, char * argv[]) { REQUEST req; RESPONSE resp; sprintf (mq_farmer, "/mq_request_%s_%d", "foo", getpid()); sprintf (mq_worker, "/mq_response_%s_%d", "bar", getpid()); //define attr struct mq_attr attr; attr.mq_maxmsg= 10; attr.mq_msgsize = sizeof(REQUEST); mqd_t reqQueue = mq_open(mq_farmer, O_WRONLY | O_CREAT | O_EXCL, 0600, &attr); attr.mq_msgsize = sizeof(RESPONSE); mqd_t respQueue = mq_open(mq_worker, O_WRONLY | O_CREAT | O_EXCL, 0600, &attr); // * create the child processes (see process_test() and message_queue_test()) int i; for(i = 0; i < 3; i++) { pid_t processID = fork(); if(processID < 0) { //error } else if(processID == 0) { //some code execlp("./worker","worker", getpid(), i, NULL); } } pid_t pid = fork(); if(pid < 0) { //error } else { if(pid == 0) //receiving done here { for(i = 0; i < 3; i++) { // read the messages from the worker queue mqd_t received = mq_receive (respQueue, (char *) &resp, sizeof(resp), NULL); printf("Farmer received worker response: %p\n with value %d\n", &resp, resp.b); //HERE &resp is always the same } // end worker process req.a = -1; mqd_t sent = mq_send(reqQueue, (char *) &req,sizeof(req), 0); } else //sending done here { for(i = 0; i < 3; i++) { req.a = i; mqd_t sent = mq_send(reqQueue, (char *) &req,sizeof(req), 0); } } } waitpid(pid, NULL, 0); mq_close(reqQueue); mq_close(respQueue); //clean up the message queues mq_unlink(mq_farmer); mq_unlink(mq_worker); return 0; } //worker: int main (int argc, char * argv[]) { REQUEST req; RESPONSE resp; int arg1; sscanf(argv[1], "%d", &arg1); sprintf (mq_farmer, "/mq_request_%s_%d", "foo", arg1); sprintf (mq_worker, "/mq_response_%s_%d", "bar",arg1); mqd_t reqQueue = mq_open (mq_farmer, O_RDONLY); mqd_t respQueue = mq_open (mq_worker, O_WRONLY); while (true){ //receiving mqd_t received = mq_receive (reqQueue, (char *) &req, sizeof(req), NULL); printf("Worker received %p with value %d\n", &req, req.a); //received stop signal if(req.a < 0){ printf("stopping worker\n"); break; } //waiting for farmer to fork sleep(3); //do something with request data resp.b = req.a; //send response mqd_t sent = mq_send (respQueue, (char *) &resp, sizeof (resp), NULL); printf("Worker sent response: %p\n", &resp); //HERE &resp is always different (doesn't print) } mq_close(reqQueue); mq_close(respQueue); //clean up the message queues mq_unlink(mq_farmer); mq_unlink(mq_worker); return 0; }
When you call mq_receive it places the data at the buffer pointed to by the second argument, which you give as &resp. It does not change the pointer itself. &resp is a fixed address in the parent, unless you change it, which appears unlikely from the posted code [which does not show the definition of resp], so: printf("Received worker response: %p\n", &resp); You will always get the same value. What you [probably] want to do is print what resp contains UPDATE: Okay, there were a few more bugs. The big bug is that while you can have one queue for worker-to-farmer messages (i.e. the response queue), you can not use a single queue for requests to workers. They each need their own request queue. Otherwise, a single worker can absorb/monopolize all requests, even ones that belong to others. If that happened, the farmer would likely see messages that were stamped from only that worker. This is what you're seeing, because, the first worker [probably #0] has its mq_receive complete first. It is, then, so fast that it does all of the mq_receive/mq_send before any others can get to them. It will then see a "stop" message and exit. If the others are "lucky", the first worker left the remaining stop messages in the queue. But, no request messages, so they never send a response. Also, the response queue was opened by the farmer with O_WRONLY instead of O_RDONLY. I've produced two versions of your program. One with annotations for bugs. Another that is cleaned up and working. Here's the annotated version [please pardon the gratuitous style cleanup]: #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <unistd.h> // for execlp #include <mqueue.h> // for mq typedef struct { int a; } REQUEST; typedef struct { int b; } RESPONSE; char *pgmname; static char mq_farmer[80]; static char mq_worker[80]; int main(int argc,char **argv) { REQUEST req; RESPONSE resp; ssize_t sent; pgmname = argv[0]; --argc; ++argv; sprintf(mq_farmer,"/mq_request_%s_%d","foo",getpid()); sprintf(mq_worker,"/mq_response_%s_%d","bar",getpid()); // define attr // NOTE/BUG: this can have random data in it struct mq_attr attr; attr.mq_maxmsg = 10; // NOTE/BUG: this is _the_ big one -- we're only doing a single request // queue -- each worker needs its _own_ request queue -- otherwise, a // single worker can _monopolize_ all messages for the other workers attr.mq_msgsize = sizeof(REQUEST); mqd_t reqQueue = mq_open(mq_farmer,O_WRONLY | O_CREAT | O_EXCL,0600,&attr); // NOTE/BUG: this should be opened for reading attr.mq_msgsize = sizeof(RESPONSE); mqd_t respQueue = mq_open(mq_worker,O_WRONLY | O_CREAT | O_EXCL,0600,&attr); // create the child processes (see process_test() and message_queue_test()) int i; // NOTE/BUG: we must remember the child pid numbers so we can do waitpid // later for (i = 0; i < 3; i++) { pid_t processID = fork(); if (processID < 0) { // error } else if (processID == 0) { // some code // NOTE/BUG: exec* takes strings so this is wrong execlp("./worker","worker",getpid(),i,NULL); } } // NOTE/BUG: on all mq_send/mq_receive, the return type is ssize_t and // _not_ mqd_t pid_t pid = fork(); if (pid < 0) { // error } else { // receiving done here if (pid == 0) { for (i = 0; i < 3; i++) { // read the messages from the worker queue ssize_t received = mq_receive(respQueue,(char *) &resp, sizeof(resp),NULL); printf("Farmer received worker response: %p with length %ld value %d\n", &resp,received,resp.b); // HERE &resp is always the same } // end worker process req.a = -1; sent = mq_send(reqQueue,(char *) &req,sizeof(req),0); printf("Farmer sent stop -- sent=%ld\n",sent); // NOTE/BUG: we need to exit here } // sending done here else { for (i = 0; i < 3; i++) { req.a = i; sent = mq_send(reqQueue,(char *) &req,sizeof(req),0); printf("Farmer sent to i=%d -- sent=%ld\n",i,sent); } } } // NOTE/BUG: we're waiting on the double fork farmer, but _not_ // on the actual worker pids waitpid(pid,NULL,0); mq_close(reqQueue); mq_close(respQueue); // clean up the message queues mq_unlink(mq_farmer); mq_unlink(mq_worker); return 0; } int worker_main(int argc,char *argv[]) { REQUEST req; RESPONSE resp; ssize_t sent; int arg1; // NOTE/BUG: use getppid instead sscanf(argv[1],"%d",&arg1); printf("worker: my index is %d ...\n",arg1); sprintf(mq_farmer,"/mq_request_%s_%d","foo",arg1); sprintf(mq_worker,"/mq_response_%s_%d","bar",arg1); mqd_t reqQueue = mq_open(mq_farmer,O_RDONLY); mqd_t respQueue = mq_open(mq_worker,O_WRONLY); while (1) { // receiving ssize_t received = mq_receive(reqQueue,(char *) &req, sizeof(req),NULL); printf("Worker received %p with length %ld value %d\n", &req,received,req.a); // received stop signal if (req.a < 0) { printf("stopping worker\n"); break; } // waiting for farmer to fork sleep(3); // do something with request data resp.b = req.a; // send response // NOTE/BUG: last argument is unsigned int and _not_ pointer #if 0 sent = mq_send(respQueue,(char *) &resp,sizeof(resp),NULL); #else sent = mq_send(respQueue,(char *) &resp,sizeof(resp),0); #endif printf("Worker sent response %p with length %ld value %d\n", &req,sent,req.a); // HERE &resp is always different (doesn't print) } mq_close(reqQueue); mq_close(respQueue); // clean up the message queues // NOTE/BUG: farmer should do this -- not worker mq_unlink(mq_farmer); mq_unlink(mq_worker); return 0; } Here's the cleaned up and working version. Note that, for ease/simplicity, I combined both the farmer and worker programs into a single one, using a little bit of trickery in main: #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <unistd.h> // for execlp #include <mqueue.h> // for mq typedef struct { int a; } REQUEST; typedef struct { int b; } RESPONSE; char *pgmname; int opt_x; int opt_W; #define WORKNR 3 char mqfile_to_farmer[80]; char mqfile_to_worker[80]; struct mq_attr attr; pid_t ppid; // per-worker control struct worker { pid_t wk_pid; mqd_t wk_req; char wk_mqfile[80]; }; struct worker worklist[WORKNR]; void worker(void) { REQUEST req; RESPONSE resp; ssize_t sent; ppid = getppid(); printf("worker: my index is %d ...\n",opt_W); sprintf(mqfile_to_farmer,"/mq_response_%d",ppid); sprintf(mqfile_to_worker,"/mq_request_%d_%d",ppid,opt_W); mqd_t reqQueue = mq_open(mqfile_to_worker,O_RDONLY); mqd_t respQueue = mq_open(mqfile_to_farmer,O_WRONLY); while (1) { // receiving errno = 0; ssize_t received = mq_receive(reqQueue,(char *) &req, sizeof(req),NULL); printf("Worker %d received %p with length %ld value %d -- %s\n", opt_W,&req,received,req.a,strerror(errno)); if (received < 0) exit(77); // received stop signal if (req.a < 0) { printf("stopping worker\n"); break; } // do something with request data resp.b = req.a; // send response errno = 0; sent = mq_send(respQueue,(char *) &resp,sizeof(resp),0); printf("Worker %d sent response %p with length %ld value %d -- %s\n", opt_W,&req,sent,req.a,strerror(errno)); // HERE &resp is always different (doesn't print) if (sent < 0) exit(78); } mq_close(reqQueue); mq_close(respQueue); exit(0); } void farmer(void) { REQUEST req; RESPONSE resp; ssize_t sent; struct worker *wk; ppid = getpid(); sprintf(mqfile_to_farmer,"/mq_response_%d",ppid); attr.mq_maxmsg = 10; attr.mq_msgsize = sizeof(REQUEST); mqd_t respQueue = mq_open(mqfile_to_farmer, O_RDONLY | O_CREAT | O_EXCL,0600,&attr); if (respQueue < 0) { printf("farmer: respQueue open fault -- %s\n",strerror(errno)); exit(1); } // create the child processes (see process_test() and message_queue_test()) int i; // create the separate request queues for (i = 0; i < WORKNR; i++) { wk = &worklist[i]; attr.mq_msgsize = sizeof(RESPONSE); sprintf(wk->wk_mqfile,"/mq_request_%d_%d",ppid,i); wk->wk_req = mq_open(wk->wk_mqfile,O_WRONLY | O_CREAT | O_EXCL,0600, &attr); if (wk->wk_req < 0) { printf("farmer: wk_req open fault -- %s\n",strerror(errno)); exit(1); } } for (i = 0; i < WORKNR; i++) { wk = &worklist[i]; pid_t pid = fork(); if (pid < 0) { perror("fork"); exit(9); } if (pid != 0) { wk->wk_pid = pid; continue; } // NOTE/FIX: exec* takes strings so this is the correct way if (opt_x) { char xid[20]; sprintf(xid,"-W%d",i); execlp(pgmname,pgmname,xid,NULL); perror("execlp"); exit(7); } // simulate what exec would do -- call it direct opt_W = i; worker(); } pid_t pid = fork(); if (pid < 0) { perror("fork2"); exit(5); } // receiving done here if (pid == 0) { for (i = 0; i < WORKNR; i++) { // read the messages from the worker queue ssize_t received = mq_receive(respQueue,(char *) &resp, sizeof(resp),NULL); printf("Farmer received worker response: %p with length %ld value %d\n", &resp,received,resp.b); // HERE &resp is always the same } // end worker process for (i = 0; i < WORKNR; i++) { wk = &worklist[i]; req.a = -1; sent = mq_send(wk->wk_req,(char *) &req,sizeof(req),0); printf("Farmer sent stop -- sent=%ld\n",sent); } // exit the farmer's receiver printf("farmer: receiver exiting ...\n"); exit(0); } // sending done here else { for (i = 0; i < WORKNR; i++) { wk = &worklist[i]; req.a = i; sent = mq_send(wk->wk_req,(char *) &req,sizeof(req),0); printf("Farmer sent to i=%d -- sent=%ld\n",i,sent); } // wait for farmer's receiver to complete printf("farmer: waiting for receiver to finish ...\n"); waitpid(pid,NULL,0); } mq_close(respQueue); // wait for all workers to complete for (i = 0; i < WORKNR; i++) { wk = &worklist[i]; printf("farmer: waiting for worker to finish ...\n"); waitpid(wk->wk_pid,NULL,0); mq_close(wk->wk_req); mq_unlink(wk->wk_mqfile); } // clean up the message queues mq_unlink(mqfile_to_farmer); } int main(int argc,char **argv) { char *cp; pgmname = argv[0]; --argc; ++argv; opt_W = -1; for (; argc > 0; --argc, ++argv) { cp = *argv; if (*cp != '-') break; switch (cp[1]) { case 'W': opt_W = atoi(cp + 2); break; case 'x': opt_x = ! opt_x; break; } } if (opt_W >= 0) worker(); else farmer(); return 0; } UPDATE #2: Here's a version that demonstrates single vs. multiple request queues. The workers now check the destination id in the message they receive matches their worker number. If you just run it with no options, you'll get multiple queues and the "good" output. If you run it with -b [and optionally -s] you'll get a single request queue and the program will see misrouted messages (e.g. worker 0 grabs a message intended for worker 1). Single queue is a subset. As long as workers are "equal", it's okay. But, if they're not (e.g. one worker can do things others can't), being able to queue to the correct worker is important. An example would be a network node that has special FPGA assisted calculation hardware that other ones don't and some requests need that acceleration. Also, single queue is self balancing by the workers. That is one form of scheduling, but there are other models. (e.g. the farmer wants to retain control of the distribution of labor). Or, the farmer has to stop one worker and keep the others going (e.g. the system being stopped will be powered off for maintenance). #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> #include <time.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <unistd.h> // for execlp #include <mqueue.h> // for mq typedef unsigned int u32; typedef struct { u32 seqno; // sequence number int toval; // destination id int fmval; // responder worker id } request_t; char *pgmname; int opt_b; // 1=broadcast int opt_i; // 1=ignore errors int opt_x; // 1=do execlp int opt_s; // number of ms to sleep int opt_S; // sequence maximum int opt_W; // worker xid #define WORKNR 3 #define MAXMSG 10 char mqfile_to_farmer[80]; mqd_t respQueue; char mqfile_to_worker[80]; mqd_t reqQueue; struct mq_attr attr; pid_t ppid; pid_t curpid; pid_t pidrcvr; // per-worker control typedef struct { int wk_xid; pid_t wk_pid; mqd_t wk_req; u32 wk_seqno; char wk_mqfile[80]; } worker_t; worker_t worklist[WORKNR]; #define FORALL_WK \ wk = &worklist[0]; wk < &worklist[WORKNR]; ++wk #define sysfault(_fmt...) \ do { \ printf(_fmt); \ if (ppid) \ kill(ppid,SIGUSR1); \ exit(1); \ } while (0) void _sysfault(void) { __asm__ __volatile__("" :::); } #define logprt(_fmt...) \ do { \ int sverr = errno; \ _logprt(); \ printf(_fmt); \ errno = sverr; \ } while (0) int logxid; double logzero; void loginit(int xid) { logxid = xid; } void _logprt(void) { struct timespec ts; double sec; clock_gettime(CLOCK_REALTIME,&ts); sec = ts.tv_nsec; sec /= 1e9; sec += ts.tv_sec; if (logzero == 0) logzero = sec; sec -= logzero; switch (logxid) { case WORKNR: printf("%.9f LOG F: ",sec); break; case WORKNR + 1: printf("%.9f LOG R: ",sec); break; default: printf("%.9f LOG W%d: ",sec,logxid); break; } } void logexit(int code) { exit(code); } void allwait(void) { worker_t *wk; // wait for farmer's receiver to complete if (pidrcvr) { logprt("farmer: waiting for receiver to finish ...\n"); waitpid(pidrcvr,NULL,0); pidrcvr = 0; } for (FORALL_WK) { if (wk->wk_pid) { logprt("farmer: waiting for worker %d to finish ...\n",wk->wk_xid); waitpid(wk->wk_pid,NULL,0); wk->wk_pid = 0; } if (opt_b) continue; logprt("farmer: closing and removing worker queue ...\n"); mq_close(wk->wk_req); mq_unlink(wk->wk_mqfile); } } void sighdr(int signo) { worker_t *wk; switch (signo) { case SIGUSR1: // request to master logprt("sighdr: got master stop signal ...\n"); if (pidrcvr) kill(pidrcvr,SIGUSR2); for (FORALL_WK) { if (wk->wk_pid) kill(wk->wk_pid,SIGUSR2); } allwait(); logprt("farmer: abnormal termination\n"); logexit(1); break; case SIGUSR2: // request to slaves logexit(1); break; } } void reqopen(mqd_t *fdp,const char *file,int flag) { mqd_t fd; int err; attr.mq_maxmsg = MAXMSG; attr.mq_msgsize = sizeof(request_t); fd = *fdp; if (fd >= 0) mq_close(fd); fd = mq_open(file,flag | O_CREAT,0600,&attr); if (fd < 0) sysfault("reqopen: %s open fault -- %s\n",file,strerror(errno)); err = mq_getattr(fd,&attr); if (err < 0) sysfault("reqopen: %s getattr fault -- %s\n",file,strerror(errno)); if (attr.mq_msgsize != sizeof(request_t)) sysfault("reqopen: %s size fault -- mq_msgsize=%ld siz=%ld\n", file,attr.mq_msgsize,sizeof(request_t)); logprt("reqopen: open -- file='%s' fd=%d\n",file,fd); *fdp = fd; } void worker(int execflg); void farmer(void) { request_t req; request_t resp; ssize_t sent; worker_t *wk; u32 seqno; int xid; ppid = getpid(); curpid = ppid; loginit(WORKNR); sprintf(mqfile_to_farmer,"/mq_response_%d",ppid); sprintf(mqfile_to_worker,"/mq_request_%d",ppid); respQueue = -1; reqopen(&respQueue,mqfile_to_farmer,O_RDONLY | O_CREAT | O_EXCL); reqQueue = -1; if (opt_b) reqopen(&reqQueue,mqfile_to_worker,O_WRONLY | O_CREAT | O_EXCL); // create the separate request queues xid = 0; for (FORALL_WK) { wk->wk_xid = xid++; if (opt_b) { logprt("farmer: common request queue -- reqQueue=%d\n",reqQueue); wk->wk_req = reqQueue; continue; } sprintf(wk->wk_mqfile,"/mq_request_%d_%d",ppid,wk->wk_xid); wk->wk_req = -1; reqopen(&wk->wk_req,wk->wk_mqfile,O_WRONLY | O_CREAT | O_EXCL); logprt("farmer: separate request queue -- wk_req=%d\n",wk->wk_req); } // fork the workers for (FORALL_WK) { pid_t pid = fork(); if (pid < 0) sysfault("farmer: fork fault -- %s\n",strerror(errno)); if (pid != 0) { wk->wk_pid = pid; continue; } // NOTE/FIX: exec* takes strings so this is the correct way if (opt_x) { char opt[2][20]; sprintf(opt[0],"-b%d",opt_b); sprintf(opt[1],"-W%d",wk->wk_xid); execlp(pgmname,pgmname,opt[0],opt[1],NULL); sysfault("farmer: execlp error -- %s\n",strerror(errno)); } // simulate what exec would do -- call it direct opt_W = wk->wk_xid; worker(0); } pidrcvr = fork(); if (pidrcvr < 0) sysfault("farmer: fork2 error -- %s\n",strerror(errno)); // receiving done here if (pidrcvr == 0) { curpid = getpid(); loginit(WORKNR + 1); for (int i = 0; i < (WORKNR * opt_S); i++) { // read the messages from the worker queue ssize_t received = mq_receive(respQueue,(char *) &resp, sizeof(resp),NULL); wk = &worklist[resp.fmval]; logprt("received worker response: length %d fmval=%d seqno=%u wk_seqno=%u\n", (int) received,resp.fmval,resp.seqno,wk->wk_seqno); if (received < 0) { if (! opt_i) sysfault("farmer: received fault -- %s\n",strerror(errno)); } if (resp.seqno != wk->wk_seqno) { logprt("sequence fault\n"); if (! opt_i) sysfault("farmer: sequence fault\n"); } ++wk->wk_seqno; } // send stop to worker processes for (FORALL_WK) { req.toval = -1; sent = mq_send(wk->wk_req,(char *) &req,sizeof(req),0); logprt("Farmer sent stop -- wk_xid=%d sent=%d\n", wk->wk_xid,(int) sent); if (sent < 0) { if (! opt_i) sysfault("farmer: send fault on stop -- %s\n", strerror(errno)); } } // exit the farmer's receiver logprt("farmer: receiver exiting ...\n"); logexit(0); } // sending done here else { for (seqno = 0; seqno < opt_S; ++seqno) { for (FORALL_WK) { wk->wk_seqno = seqno; req.seqno = seqno; req.toval = wk->wk_xid; sent = mq_send(wk->wk_req,(char *) &req,sizeof(req),0); logprt("Farmer sent to wk_xid=%d wk_req=%d -- sent=%d\n", wk->wk_xid,wk->wk_req,(int) sent); if (sent < 0) { if (! opt_i) sysfault("farmer: send fault -- %s\n",strerror(errno)); } } } } mq_close(respQueue); // wait for all workers to complete allwait(); // clean up the message queues mq_unlink(mqfile_to_farmer); logprt("farmer: complete\n"); logexit(0); } void worker(int execflg) { request_t req; request_t resp; ssize_t sent; u32 seqno; int slpcnt; if (execflg) ppid = getppid(); curpid = getpid(); loginit(opt_W); logprt("worker: my index is %d ...\n",opt_W); attr.mq_maxmsg = MAXMSG; sprintf(mqfile_to_farmer,"/mq_response_%d",ppid); reqopen(&respQueue,mqfile_to_farmer,O_WRONLY); if (opt_b) sprintf(mqfile_to_worker,"/mq_request_%d",ppid); else sprintf(mqfile_to_worker,"/mq_request_%d_%d",ppid,opt_W); reqopen(&reqQueue,mqfile_to_worker,O_RDONLY); seqno = 0; slpcnt = opt_s; slpcnt *= 1000; slpcnt *= opt_W; while (1) { if (slpcnt > 0) { logprt("sleep %d\n",slpcnt); usleep(slpcnt); slpcnt = 0; } // receiving errno = 0; ssize_t received = mq_receive(reqQueue,(char *) &req, sizeof(req),NULL); logprt("received length %d -- seqno=%u toval=%d\n", (int) received,req.seqno,req.toval); if (received < 0) sysfault("worker: mq_receive fault -- %s\n",strerror(errno)); // received stop signal if (req.toval < 0) { logprt("stopping ...\n"); break; } if (req.toval != opt_W) { logprt("misroute\n"); if (! opt_i) sysfault("worker: misroute fault\n"); } if (req.seqno != seqno) { logprt("sequence fault\n"); if (! opt_i) sysfault("worker: sequence fault\n"); } // do something with request data resp.seqno = req.seqno; resp.toval = req.toval; resp.fmval = opt_W; // send response errno = 0; sent = mq_send(respQueue,(char *) &resp,sizeof(resp),0); logprt("sent response with length %d -- seqno=%u toval=%d\n", (int) sent,req.seqno,resp.toval); // HERE &resp is always different (doesn't print) if (sent < 0) sysfault("worker: mq_send fault -- %s\n",strerror(errno)); ++seqno; } mq_close(reqQueue); mq_close(respQueue); logexit(0); } int main(int argc,char **argv) { char *cp; pgmname = argv[0]; --argc; ++argv; opt_W = -1; opt_S = 3; reqQueue = -1; respQueue = -1; signal(SIGUSR1,sighdr); signal(SIGUSR2,sighdr); for (; argc > 0; --argc, ++argv) { cp = *argv; if (*cp != '-') break; switch (cp[1]) { case 'b': // broadcast mode (single request queue) cp += 2; opt_b = (*cp != 0) ? atoi(cp) : 1; break; case 'i': // ignore errors cp += 2; opt_i = (*cp != 0) ? atoi(cp) : 1; break; case 'S': // sequence maximum cp += 2; opt_S = (*cp != 0) ? atoi(cp) : 3; break; case 's': // sleep mode (milliseconds) cp += 2; opt_s = (*cp != 0) ? atoi(cp) : 3; break; case 'W': // worker number cp += 2; opt_W = atoi(cp + 2); break; case 'x': // use execlp opt_x = ! opt_x; break; } } if (opt_W >= 0) worker(1); else farmer(); return 0; }
segmentation fault occur on thread program
I am new in thread program. I wrote a C program for executing threads which reverse the command line string and print the both original and reversed string. My program is here: #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<pthread.h> #include<string.h> typedef struct { char *input_string; char *rev_string; }data; void* rev_string(void* arg) { int len = 0,index1 = 0, index2 = 0; data* names = NULL; /*bject creation*/ names = (data*)malloc(sizeof(data)); if( NULL == names) { printf("malloc failure\n"); exit(1); } printf("thread recvd = %s\n",(char*)arg); len = strlen((char*)arg); names->input_string = (char*)malloc(sizeof(char)*(len+1)); if( NULL == names->input_string) { printf("malloc failure\n"); exit(1); } strncpy(names->input_string,(char*)arg,len); /*copying input_string to the struct*/ names->rev_string = (char*)malloc(sizeof(char)*(len+1)); if( NULL == names->rev_string) { printf("malloc failure\n"); exit(1); } for(index1 = len-1 ; index1 >= 0 ; index1--) { names->rev_string[index2] = names->input_string[index1]; index2++; } pthread_exit((void*)names); } Main program: int main(int argc,char* argv[]) { int no_of_strings = 0, len = 0, status = 0, ret = 0 , index = 0; pthread_t id[index]; /*thread identifier*/ void* retval = NULL; /*retval to store the value returned by thread job */ data *strings = NULL;/*object creation*/ if(1 >= argc) { printf(" please do enter the commands as of below shown format\n"); printf("<exe.c> <string1> <string2> ...<string(N)>\n"); exit(1); } no_of_strings = argc - 1 ; /* no of strings entered */ /*creation of threads*/ for(index = 0; index < no_of_strings ;index++) { status = pthread_create(&id[index],NULL,rev_string,(void*)argv[index + 1]); if(status != 0) { printf("ERROR in creating thread\n"); exit(1); } else { printf("thread %d created\n",index+1); } } for(index = 0 ;index < no_of_strings;index++) { ret = pthread_join(id[index],&retval); if(ret) { printf("Error in joining %d\n", ret); exit(1); } printf("the input_string = %s and its reverse = %s\n",((data*)retval)->input_string,((data*)retval)->rev_string); } // free(retval->input_string); // free(retval->rev_string); // free(retval); pthread_exit(NULL); exit(0); } It works on 2 string from command line argument. But got segmentation fault when more than strings. Why? Any errors? Help me.
pthread_t id[index]; id has zero length because index == 0. So any assignment to its elements is undefined behavior. Initialize the array with some positive length, e.g: const int MAX_THREADS = 10; pthread_t id[MAX_THREADS]; /*thread identifier*/
Why is *randNum being incremented?
I know what every command does within my code, I just don't know the reasons they're there in the first place. This is insanely difficult to search answers for as my questions relate mostly to my own program. Apologies if it's still un-answerable, I will endeavor to improve my future questions :). I need to write a program that can communicate across shared memory, taking turns to create and delete processes. I'm trying to understand the piece of code I was given, in particular the bit below. At the very bottom I've included the whole producer code in case it helps anyone answer my question. THE QUESTION: Why is *randNum incremented past 101 when later, the condition for it to print the output IS it being equal to 101? Does this hint at the Consumer having to change the value contained in the location *randNum in order for the condition to be met? for(A = 0; A < size; A++) // for loop to reset all priority values so that they are clear to be used in the next set { *randNum = 101; *randNum++; } The if command later on: if(*randNum == 101) { *randNum = rand() % (100 - 1) + 1; *pidNum = getpid(); printf("priority: %d Process ID: %d \n", *randNum, *pidNum); x = 1; } As promised, full program below for completion purposes (trying to make it easier on you and prevent questions; also to provide context) #include <stdio.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <unistd.h> void shm2sz(int size); int main(int argc, char *argv[]) { int shmid, A, B, count, *shm, *randNum, *pidNum, pid, *memSig; key_t key; int size = atoi(argv[1]); int shmsz = (size * 2) + 1; // declaring size of shared mem to be twice the size of user input, + 1 for owner ID int x = 0; int noToCreate = atoi(argv[2]); shm2sz(shmsz); key = 2060; // Identifier key for SharedMem shmid = shmget(key, shmsz, IPC_CREAT | 0666); //creating Sharedmem if(shmid < 0) // variable if sharedmem is less than 0, print error. { perror("shmget"); // eror mesage print exit(1); } shm = shmat(shmid, NULL, 0); //Attach to shared mem, if fails.. proceed with error message if(shm == (int *) -1) // eror message { perror("shmat"); exit(1); } randNum = shm; // declare randNum equal to shm pidNum = shm + size; // set pid to the first bit of the second part of the shared mem memSig = shm + shmsz; // set memsig as final value in shared mem *memSig = 0; for(A = 0; A < size; A++) // for loop to reset all priority values so that they are clear to be used in the next set { *randNum = 101; *randNum++; } count = 0; // set count back to 0 randNum = shm; //check randNum equal to shm pidNum = shm + size; while(*memSig != 2) { while(*memSig == 1) // set memsignature to sleep while.. { sleep(1); } for(B = 0; B < noToCreate; B++) { pid = fork(); if(pid == -1) { perror("Error forking"); exit(1); } else if(pid > 0) { wait(0); } else { srand(getpid()); while(x == 0) { if(*randNum == 101) { *randNum = rand() % (100 - 1) + 1; *pidNum = getpid(); printf("priority: %d Process ID: %d \n", *randNum, *pidNum); x = 1; } else { *randNum++; *pidNum++; } } exit(0); } } /* Closes main for loop */ if(*memSig == 0) { *memSig = 1; } } /* Closes main while loop */ } void shm2sz(int size) { int shmid, *shm2; key_t key; key = 9876; shmid = shmget(key, 2, IPC_CREAT | 0666); if(shmid < 0) { perror("shmget2"); exit(1); } shm2 = shmat(shmid, NULL, 0); if(shm2 == (int *) -1) { perror("shmat2"); exit(1); } *shm2 = size; }
The operator precedence for the postfix increment operator is higher than the pointer dereference operator. This means that *randNum++ actually increases the pointer randNum. If you want to increment the value pointed to by randNum you have to use parentheses: (*randNum)++;