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)++;
Related
I´m having some trouble, trying to read the shmem.
The program writing the data is giving me no error so i don't know what to do anymore.
typedef struct
{
long id;
} data;
data *dados[MAX];
int main()
{
key_t key = 5678;
int shmid;
if (shmid = shmget(key, MAX * sizeof(data),0666) < 0)
{
perror("shmget error");
return 1;
}
if((*dados = shmat(shmid,NULL,0)) == (void*) -1){
perror("shmat");
}
for (int i = 0; i < MAX; i++)
{
printf("time:%ld\n", dados[i]->id);
printf("passed %d",i);
}
return 0;
}
if (shmid = shmget(key, MAX * sizeof(data),0666) < 0)
According to C operator order of precedence the < operator has higher precedence than the = operator. Thus the above code actually assigns the boolean shmget(key, MAX * sizeof(data),0666) < 0 result to shmid.
Use explicit bracketing to get the desired result:
if ((shmid = shmget(key, MAX * sizeof(data),0666)) < 0)
I have a large file (around 1,000,000 characters) in the format "AATACGTAGCTA" and a subsequent file, such as "CGTATC" (10,240 characters). I want to find the largest match of the subsequence within the main sequence. A full, 100% subsequence match may not exist, this is not guaranteed. For the sake of a smaller example, the above would output: Longest match is 4/6 starting at position 5.
I'm working on my C basics, and would like to implement it like so:
The user chooses how many processes they would like to split the work
into.
Each process does 1/nth of the work and updates the shared memory
values located in the struct.
The longest match (it may not be all characters) is reflected in the
struct, as well as it's starting position, and how many
characters were matched. See output below.
Code
#define _GNU_SOURCE
#include <limits.h>
#include <stdio.h>
#include <errno.h>
#include <semaphore.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/shm.h>
typedef struct memoryNeeded {
int start_pos, total_correct;
char sequence[1038336];
char subsequence[10240];
sem_t *sem;
} memoryNeeded;
// Used to check all arguments for validity
int checkArguments(char* p, int argc) {
char *prcs;
errno = 0;
int num;
long conv = strtol(p, &prcs, 10);
if (errno!= 0 || *prcs != '\0' || conv > INT_MAX || conv > 50) {
puts("Please input a valid integer for number of processes. (1-50)");
exit(1);
} else {
num = conv;
if (argc != 4) {
puts("\nPlease input the correct amount of command line arguments (4) in"
"the format: \n./DNA (processes) (sequence) (subsequence)\n");
exit(1);
} else
printf("Looking for string using %d processes...\n", num);
return(num);
}
}
int main (int argc, char* argv[]) {
int processes = checkArguments(argv[1], argc);
key_t shmkey;
int procNumber, shmid, pid;
FILE *sequence;
FILE *subsequence;
char *buf1, *buf2;
// Create shared memory
size_t region_size = sizeof(memoryNeeded);
shmkey = ftok("ckozeny", 5);
shmid = shmget(shmkey, region_size, 0644 | IPC_CREAT);
if (shmid < 0) {
perror("shmget\n");
exit(1);
}
// Create structure in shared memory, attach memory and open semaphore
memoryNeeded *mn;
mn = (memoryNeeded *)shmat(shmid, NULL, 0);
mn->sem = sem_open("sem", O_CREAT | O_EXCL, 0644, 1);
sequence = fopen(argv[2], "r");
subsequence = fopen(argv[3], "r");
// Get file sizes
fseek(sequence, 0L, SEEK_END);
int sz1 = ftell(sequence);
rewind(sequence);
fseek(subsequence, 0L, SEEK_END);
int sz2 = ftell(subsequence);
rewind(subsequence);
// Read files into 2 buffers, which are put into struct mn
buf1 = malloc(sz1);
buf2 = malloc(sz2);
if (sz1 != fread(buf1, 1, sz1, sequence)) {
free(buf1);
}
if (sz2 != fread(buf2, 1, sz2, subsequence)) {
free(buf2);
}
// Initialize struct with necessary values
mn->start_pos = 0;
mn->total_correct = 0;
strncpy(mn->sequence, buf1, sz1);
strncpy(mn->subsequence, buf2, sz2);
fclose(sequence);
fclose(subsequence);
// Begin n forks
for (procNumber = 0; procNumber < processes; procNumber++) {
pid = fork();
if (pid < 0) {
sem_unlink("sem");
sem_close(mn->sem);
printf ("Fork error.\n");
} else if (pid == 0)
break;
}
if (pid != 0) {
while ((pid = waitpid (-1, NULL, 0))){
if (errno == ECHILD)
break;
}
printf("Best match is at position %d with %d/10240 correct.", mn->start_pos, mn->total_correct);
printf ("\nParent: All children have exited.\n");
sem_unlink("sem");
sem_close(mn->sem);
shmdt(mn);
shmctl(shmid, IPC_RMID, 0);
exit(0);
} else {
// this child process will do its 1/nth of the work
sem_wait(mn->sem);
printf ("Child(%d) is in critical section.\n", procNumber);
sleep(1);
int i = 0;
int longest, count = 0;
for (i = 0; i < sz1; i += processes) {
for (int j = 0; j < sz2; j += processes) {
count = 0;
while (mn->sequence[i+j] == mn->subsequence[j]) {
count++;
j++;
}
if (count > longest) {
longest = count;
}
}
}
// If local match is longer than that of the struct, update and unlock
if (longest > mn->total_correct) {
mn->total_correct = count;
mn->start_pos = (i - count);
sem_post(mn->sem);
} else
// If not - unlock and let next process go
sem_post(mn->sem);
exit(0);
}
return 1;
}
The current child code is more or less "pseudocode". I've put it together how it makes sense in my head. (I'm aware this may not be correct or function as intended.) My question is in regard to the child code algorithm near the bottom.
How do I implement this so each child does 1/nth of the work, and finds the longest match, even though it may not match 100%?
Final output would be:
./DNA 6 sequence1 subsequence1
Looking for string using 6 processes...
Best match is at position 123456 with 9876/10240 correct.
Thanks.
So i'm currently trying to code in unix using shared memory and the fork() function, I have an array of 10 structs and I would like to put that array into shared memory so that it can be accessed by a client program. I was hoping someone could point me in the right direction on how to do this.
the code I currently have is:
// Compiler Directives
// Standard Library Inclusions
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <time.h>
//Other Inclusions
struct strProcess
{
int nPriority;
int nPid;
};
// Function Prototypes (if not included within a header file)
int frand (int nInput);
int finval (int nInput);
void fsortasc(struct strProcess pArray[],int nInput);
// Main
int main(void)
{
// Variable Declarations
int nShmid,i,arraySize,nRpriority,j, nInput;
key_t nKey;
char *ptrshm, *ptrs;
int nSize;
pid_t pid;
struct strProcess pArray[10];
struct strProcess *Array;
Array = pArray;
// Code start
nKey = 5678;
FILE *f = fopen("logfile.txt", "w");
if (f == NULL)
{
printf("Error opening file!\n");
exit(1);
}
printf("please enter the amount of processes to create for this cycle between 1 and 10 \n");
scanf("%d",&nInput);
if (nInput <= 0 || nInput > 10)
{
nInput = finval(nInput);
}
printf("%d", nInput);
nSize = sizeof(pArray) * 10;
//create segment
if ((nShmid = shmget(nKey,nSize, IPC_CREAT | 0666)) <0)
{
perror("shmget");
exit(1);
}
printf("segment created \n\n");
fprintf(f, "shared memory segment created");
Array *pArray = shmat(shmid,NULL, 0);
if (Array* pArray (-1))
{
perror("shmat");
exit(1);
}
printf("segment attached \n\n");
fprintf(f, "shared memory segment attached");
for(i = 0 ; i < nInput; i++)
{
if ((pid = fork()) < 0)
{
perror("fork");
exit(1);
}
if (pid == 0)
{
Array[i].nPid = getpid();
nRpriority = frand(nInput);
Array[i].nPriority = nRpriority;
printf("print job created with Pid %d and priority number %d",
getpid(), nRpriority);
fprintf(f, "print job created with Pid %d and priority number %d",
getpid(), nRpriority);
}
}
fprintf(f, " %d processes have been created", nInput);
fsortasc(pArray, nInput); /*sort array into ascending order by nRpriority values*/
// Function Definitions - in alphabetical order
int finval (int nInput)
{
while(nInput <= 0 || nInput > 10)
{
printf("please enter a number between 1 and 10 \n");
scanf("%d", &nInput);
}
return nInput;
}
int frand (int nInput)
{
int nRand;
nRand = (rand() % nInput)+1; /*set nRand == a random number
inbetween nInput and 1*/
return nRand; /*return the random number*/
}
void fsortasc(struct strProcess pArray[],int nInput)
{
struct strProcess temp; /*temporary storage for elements being swapped*/
int i, j;
for (i = 0; i < nInput - 1; i++)
{
for (j = 0; j < (nInput - 1-i); j++)
{
if (pArray[j].nPriority > pArray[j + 1].nPriority) /*if the current element is greater than the next element*/
{
temp = pArray[j];
pArray[j] = pArray[j + 1];
pArray[j + 1] = temp;
}
}
}
I have an array of 10 structs and I would like to put that array into shared memory ? It's very simple, first create array 10 struct variable and then create the shared memory using shmget of required size and then attach that shared memory with pointer and finally copy array of 10 structs into pointer attached with shmat. I added below simple code to understand your requirement.
typedef struct company {
int emp_id;
}cmp;
int main(int argc,char *argv[]) {
cmp cmp_info[10];
int shm_id, sze = sizeof(cmp_info) ,i;
/* I have an array of 10 structs -- with some data like emp_id*/
for(i=0 ;i<10 ;i++) {
printf("\n enter emp % Id \n",i);
scanf("%d",&cmp_info[i].emp_id);
}
/* create the shared memory of 'sze' size. */
shm_id = shmget(10,sze, IPC_CREAT | 0664);
perror("shmget");
/* attach the shared memory with shm_id */
cmp *shm_ptr = shmat(shm_id, NULL, 0);
perror("shmat");
/* I have an array of 10 structs and I would like to put that array into shared memory */
shm_ptr = cmp_info;//now shared memory contains array of 10 struct data
/** print using shm_ptr to verify **/
for(i=0;i<10;i++) {
printf("Employee[%d] Id is : [%d]\n",i,shm_ptr[i].emp_id);
}
/* once above things are done clients program can read from shared memory */
/** finaly de-atach the shared memory */
shmdt(shm_ptr);
}
Below snapshot is for your code, Explanation is in comments.
struct strProcess {
int nPriority;
int nPid;
};
int main(int argc,char *argv[]) {
// Variable Declarations
int nShmid,i,arraySize,nRpriority,j, nInput;
key_t nKey;
char *ptrshm, *ptrs;
int nSize;
struct strProcess pArray[10];//array of 10 structure
struct strProcess *Array;
//Array = pArray;
nKey = 5678;
FILE *f = fopen("logfile.txt", "w");
if(f == NULL) {
printf("Error opening file!\n");
exit(1);
}
nSize = sizeof(pArray);
//create segment
if((nShmid = shmget(nKey,nSize, IPC_CREAT | 0666)) < 0) {
perror("shmget");
exit(1);
}
else {
perror("shmget");
fprintf(f, "\n shared memory segment created\n");
}
Array = shmat(nShmid, NULL, 0);
perror("shmat");
/** loop to create exaCtly 10 process */
nInput = 10; /** call finval function **/
for(i = 0 ; i < nInput; i++) {
if(fork() == 0) {
srand(getpid());
Array[i].nPid = getpid();
nRpriority = rand()%10 + 1;//putting random no b/w 1 to 10..u can call your function also
Array[i].nPriority = nRpriority;
fprintf(f, "\nprint job created with Pid [%d] and priority number [%d]\n",
Array[i].nPid, Array[i].nPriority);
break;//must to avoid repeating
}
else {
;//parent does nothing
}
}
shmdt(Array);
//fprintf(f,"\n total [%d] processes have been created\n",nInput);
/* call fsortasc(pArray, nInput); */
fclose(f);
}
I hope it helps.
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).
The task was to create simulation of warehouse's work. Producers (in an amount of argv[2]) create random number of "goods" (totally argv[1]), and consumers (in an amount of argv[3]) get random number of these goods. The full code is below.
I got segmentation error and tried to debug it and got the following:
Program received signal SIGSEGV, Segmentation fault.
__new_sem_init (sem=0x37, pshared=0, value=1) at sem_init.c:44
44 sem_init.c: No such file or directory
I think the problem is in address-of operator here
sem_init(&(shared->mutex), 0, 1);
How should I change the code to make it work?
Thanks a lot!
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/mman.h>
#define NBUFF 10
#define MAXNTHREADS 100
#define min( a, b ) ( ( a < b) ? a : b )
int nitems, nproducers, nconsumers;
typedef struct shared_s
{
int buff[NBUFF];
int nput;
int nputval;
int nget;
int ngetval;
sem_t mutex, nempty, nstored;
} sharedtype;
int main(int argc, char **argv)
{
sharedtype * shared;
key_t key;
int shmid, semid;
int i, j, prodcount[MAXNTHREADS], conscount[MAXNTHREADS];
shared = mmap(NULL, sizeof(sharedtype),
PROT_READ | PROT_WRITE, MAP_SHARED, -1, 0);
/* Wrong argv */
if (argc != 4)
{
printf("usage: newconsumer <#items> <#producers> <#consumers>\n");
exit(1);
}
nitems = atoi(argv[1]);
nproducers = min(atoi(argv[2]), MAXNTHREADS);
nconsumers = min(atoi(argv[3]), MAXNTHREADS);
pid_t chpidpr [nproducers];
pid_t chpidcon [nconsumers];
/* initilising semaphores */
sem_init(&(shared->mutex), 0, 1);
sem_init(&(shared->nempty), 0, NBUFF);
sem_init(&(shared->nstored), 0, 0);
for (i = 0; i < nproducers; i++) {
prodcount[i] = 0;
switch (chpidpr[i] = fork())
{
case -1:
printf("fork error");
return 1;
case 0:
for (;;)
{
sem_wait(&shared->nempty);
sem_wait(&shared->mutex);
if (shared->nput >= nitems)
{
sem_post(&(shared->nstored));
sem_post(&(shared->nempty));
sem_post(&(shared->mutex));
return 0;
}
shared->buff[(shared->nput) %NBUFF] = shared->nputval;
(shared->nput)++;
(shared->nputval)++;
sem_post(&(shared->mutex));
sem_post(&(shared->nstored));
prodcount[i] += 1;
}
}
}
for (i = 0; i < nproducers; i++)
{
printf("producer count[%d] = %d\n", i, prodcount[i]);
}
for (i = 0; i < nconsumers; i++) {
conscount[i] = 0;
switch (chpidcon[i] = fork())
{
case -1:
printf("error");
return 1;
case 0:
for (;;)
{
sem_wait(&(shared->nstored));
sem_wait(&(shared->mutex));
if (shared->nget >= nitems)
{
sem_post(&(shared->nstored));
sem_post(&(shared->mutex));
return 0;
}
j = shared->nget % NBUFF;
if (shared->buff[j] != shared->ngetval)
{
printf("error: buff[%d] = %d\n", j, shared->buff[j]);
}
shared->nget++;
shared->ngetval++;
sem_post(&(shared->mutex));
sem_post(&(shared->nempty));
conscount[i] += 1;
}
}
}
for (i = 0; i < nconsumers; i++)
{
printf("consumer count[%d] = %d\n", i, conscount[i]);
}
/* destroying semaphores */
sem_destroy(&(shared->mutex));
sem_destroy(&(shared->nempty));
sem_destroy(&(shared->nstored));
exit(0);
}
It looks like your mmap call has failed and return -1. You aren't checking for this condition.
I did a quick addition, and it looks like mutex is at an offset of 56, or 0x38 from the base of sharedtype. Based on the crash report, sem = 0x37, which would be the address of shared->mutex if shared == -1.
I can't find any documentation on why one would call mmap with fd == -1, but I think this may be the source of the issue, combined with not validating the result.