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)++;

Resources