Producer Consumer using semaphores-c - c

Problem:
All processes have an array of elements.
Producer stores a value in his array.
All consumers(n) must store this value on their array before a producer can produce additional element.
All consumers should store the element and wait until the producer creates a new one.
So in my implementation I'm using three semaphores: all(as a barrier)=1, new=0 and a mutex=1. I'm also using a shared counter=0 to count how many consumers have read the element.
Code:
#include <time.h>
#include <sys/shm.h>
#include "stdio.h"
#include "sys/sem.h"
#include "stdlib.h"
#include "unistd.h"
int sem_id;
int shmid;
typedef struct sharedMemory{
int value;
}sharedMemory;
union semun {
int val;
struct semid_ds * buf;
unsigned short * array;
};
#define M 4
#define N 2
typedef enum semIndex{
mutex= 0,
all=1,
new=2
}semIndex;
int sem_init(semIndex index,int val){
union semun sem_union;
sem_union.val = val;
if (semctl(sem_id, index, SETVAL, sem_union) == -1) return 0;
return 1;
}
int up(semIndex index) {
struct sembuf sem_b;
sem_b.sem_num = index;
sem_b.sem_op = 1;
if (semop(sem_id, &sem_b, 1) == -1) {
perror("Failed to up");
return 0;
}
return 1;
}
int down(semIndex index) {
struct sembuf sem_b;
sem_b.sem_num = index;
sem_b.sem_op = -1;
if (semop(sem_id, &sem_b, 1) == -1) {
perror("Failed to up");
return 0;
}
return 1;
}
void *getShMemory(int memory) {
shmid = shmget((key_t)1234+memory, sizeof(sharedMemory), 0666 | IPC_CREAT);
if (shmid == -1) {
fprintf(stderr, "shmget failed\n");
exit(EXIT_FAILURE);
}
void* shared_memory = shmat(shmid, (void *)0, 0);
if (shared_memory == (void *)-1) {
fprintf(stderr, "shmat failed\n");
exit(EXIT_FAILURE);
}
return shared_memory;
}
int main(void){
srand(getpid() + rand()%500);
int *array = malloc(M * sizeof(int));
for (int i = 0; i < M; ++i) {
array[i] = rand() % 20;
}
sem_id = semget(6846, 3, 0666 | IPC_CREAT);
sharedMemory *sharedMem = (sharedMemory*) getShMemory(2);
sem_init(all,1);
sem_init(mutex,1);
sem_init(new,0);
pid_t pid = fork();
if (pid>0){
for (int i = 0; i < M; ++i) {
down(all);
down(mutex);
sharedMem->value = array[i];
up(mutex);
up(new);
}
for (int j = 0; j < M; ++j) {
printf("%d,",array[j]);
}
putchar('\n');
}
else{
sem_id = semget(6846, 3, 0666 | IPC_CREAT);
int *array = malloc(M*sizeof(int));
sharedMemory* consumerMem = (sharedMemory*)getShMemory(1);
down(new);
consumerMem->value = 0;
for(int i=0;i<N;++i){
if(fork() == 0) {
for (int j = 0; j < M; ++j) {
down(mutex);
consumerMem = (sharedMemory*)getShMemory(1);
sharedMemory *sharedMem = (sharedMemory*) getShMemory(2);
array[j] = sharedMem->value;
consumerMem->value++;
up(mutex);
if (consumerMem->value == N) {
down(mutex);
consumerMem->value = 0;
up(mutex);
up(all); //signal producer to create new element
}
down(new); //wait for new element
up(new); //unblock one more consumer
}
for (int j = 0; j < M; ++j) {
printf("%d,",array[j]);
}
putchar('\n');
exit(0);
}
}
}
}
Sometimes it works as intended so it ought to be a race condition but I can't pinpoint it.Any clues?
Update:
I managed to run debug with Clion. I can't replicate the problem with the debugger so it's even harder to pinpoint the problem.

Related

MPI Segmentation Fault while running with 4 processes

I wrote my parallel version of unix grep program. In this program you search for patter in files given as program arguments.
In root process I calculate number of files per process and first file ID for each process. After calculations I send this values to each of root processes.
In not root process I'm receiving num of Files and first file ID and analyzing each file in analyzeFile method. In that method I send back string, which contains all lines with pattern, to root process. After collecting all data from not root precesses I print out final result.
The problem is when I try to run program with more than 3 processes. It ends up with segmentation fault.
I'm out of ideas. Valgrind does not show any error reports on base scanning.
PS. I know that code needs refactoring, but first I want to get rid of this bug.
Thanks for any help.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <mpi.h>
#define YEL "\x1B[33m"
#define BLU "\x1B[34m"
#define MAG "\x1B[35m"
#define RESET "\x1B[0m"
#define send_data_tag 1000
#define return_data_tag 1001
struct linesRange
{
int lineFrom;
int lineTo;
int posFrom;
int posTo;
};
int countNumOfLines(char *str)
{
int numOfLines = 0;
int i = 0;
while(str[i] != '\0')
{
if(str[i] == '\n')
{
++numOfLines;
}
++i;
}
return numOfLines;
}
long int findLinePos(char *str, int lineNumToFind)
{
long int linePos = 0;
long int lineNum = 0;
long int i = 0;
if(lineNumToFind == 0)
{
return linePos;
}
while(str[i] != '\0')
{
if(str[i] == '\n')
{
++lineNum;
if(lineNum == lineNumToFind)
{
linePos = i;
break;
}
}
++i;
}
return linePos;
}
long int findNextLinePos(char *str, int startPos)
{
long int i = startPos;
long int nextLinePos = 0;
while(str[i] != '\0')
{
if(str[i] == '\n')
{
nextLinePos = i;
break;
}
++i;
}
return nextLinePos;
}
bool strstrn(char *str, char *pattern, long int posStart, long int posEnd)
{
long int pos_search = 0;
long int pos_text = 0;
int len_search = strlen(pattern);
for (pos_text = posStart; pos_text < posEnd; ++pos_text)
{
if(str[pos_text] == pattern[pos_search])
{
++pos_search;
if(pos_search == len_search)
{
return true;
}
}
else
{
pos_text -= pos_search;
pos_search = 0;
}
}
return false;
}
char * searchPatternInText(char *text, char *inputPattern, char *fileName, int proc_id)
{
char *bufToAdd;
int lineNum = 0;
char * resultBuf = (char*)malloc(sizeof(char));
memset(resultBuf, 0, sizeof(char));
char * curLine = text;
while(curLine)
{
++lineNum;
char * nextLine = strchr(curLine, '\n');
if (nextLine)
*nextLine = '\0';
if(strstr(curLine, inputPattern))
{
bufToAdd = (char*)malloc(sizeof(char));
memset(bufToAdd, 0, sizeof(char));
asprintf (&bufToAdd, BLU "Ścieżka:%s\tProces:%d\n" MAG "Numer linii:%d\t" RESET "%s\n", fileName, proc_id, lineNum, curLine);
resultBuf = (char*)realloc(resultBuf, strlen(resultBuf) + strlen(bufToAdd) + 1);
strcat(resultBuf, bufToAdd);
free(bufToAdd);
}
if (nextLine)
*nextLine = '\n';
curLine = nextLine ? (nextLine+ 1) : NULL;
}
return resultBuf;
}
void analyzeFile(struct stat sb, int fd, char *fileName, char *pattern, int proc_id)
{
char *text = mmap (0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (text == MAP_FAILED) {
perror ("mmap");
return;
}
if (close (fd) == -1)
{
perror ("close");
return;
}
char *tempTxt;
tempTxt = (char*)malloc(sizeof(char) * (strlen(text) + 1));
strcpy(tempTxt, text);
tempTxt[strlen(text)] = '\0';
//munmap(text, sb.st_size);
char *result;
result = searchPatternInText(tempTxt, pattern, fileName, proc_id);
free(tempTxt);
if(proc_id != 0)
{
MPI_Send(result, strlen(result), MPI_CHAR,
0, return_data_tag, MPI_COMM_WORLD);
}
else
{
printf(result);
}
free(result);
}
int main (int argc, char *argv[])
{
int patternLen = 10;
char pattern [patternLen + 1];
float elapsed;
int numOfFiles = argc - 2;
int proc_id, num_procs, procIterator, filesIterator, root = 0;
int *numOfFilesPerProcess, *firstFileIdPerProcess;
if (argc < 3) {
fprintf (stderr, "usage: %s <file>\n", argv[0]);
return 1;
}
else
{
strncpy(pattern, argv[1], patternLen);
pattern[patternLen] = '\0';
}
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &proc_id);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Barrier(MPI_COMM_WORLD);
double startTime = MPI_Wtime();
if(proc_id == root)
{
MPI_Status statusMaster;
numOfFilesPerProcess = (int*)malloc(sizeof(int) * num_procs);
firstFileIdPerProcess = (int*)malloc(sizeof(int) * num_procs);
for(int i = 0; i < num_procs; ++i)
{
numOfFilesPerProcess[i] = 0;
firstFileIdPerProcess[i] = 0;
}
filesIterator = 0;
procIterator = 0;
while(filesIterator < numOfFiles)
{
if(procIterator == num_procs)
{
procIterator = 0;
}
++numOfFilesPerProcess[procIterator];
++procIterator;
++filesIterator;
}
firstFileIdPerProcess[0] = 2;
//pierwszy numer argumentu argv[] per proces
for(int jj = 1; jj < num_procs; ++jj)
{
firstFileIdPerProcess[jj] = firstFileIdPerProcess[jj - 1] + numOfFilesPerProcess[jj - 1];
}
for(int j = 1; j < num_procs; ++j)
{
MPI_Send(&firstFileIdPerProcess[j], 1, MPI_UNSIGNED,
j, send_data_tag, MPI_COMM_WORLD);
MPI_Send(&numOfFilesPerProcess[j], 1, MPI_UNSIGNED,
j, send_data_tag, MPI_COMM_WORLD);
}
int firstFileIdForProcess = firstFileIdPerProcess[0];
int numOfFilesForProcess = numOfFilesPerProcess[0];
int fd;
struct stat sb;
for(int i = 0; i < numOfFilesForProcess; ++i)
{
fd = open (argv[firstFileIdForProcess + i], O_RDONLY);
if ( fd == -1
|| fstat (fd, &sb) == -1
|| !S_ISREG (sb.st_mode))
{
perror("file");
}
else
{
analyzeFile(sb, fd, argv[firstFileIdForProcess + i], pattern, proc_id);
}
}
for(int ii = numOfFilesPerProcess[0]; ii < numOfFiles; ++ii)
{
int resultLen;
char *result;
MPI_Probe(MPI_ANY_SOURCE, return_data_tag, MPI_COMM_WORLD, &statusMaster);
MPI_Get_count(&statusMaster, MPI_CHAR, &resultLen);
result = (char *)malloc(sizeof(char) * resultLen + 1);
MPI_Recv( result, resultLen, MPI_CHAR,
MPI_ANY_SOURCE, return_data_tag, MPI_COMM_WORLD, &statusMaster);
result[resultLen] = '\0';
printf(result);
free(result);
}
free(numOfFilesPerProcess);
free(firstFileIdPerProcess);
}
else
{
MPI_Status statusSlave;
int firstFileIdForProcess = 0;
int numOfFilesForProcess = 0;
int fd;
struct stat sb;
MPI_Recv( &firstFileIdForProcess, 1, MPI_UNSIGNED,
root, send_data_tag, MPI_COMM_WORLD, &statusSlave);
MPI_Recv( &numOfFilesForProcess, 1, MPI_UNSIGNED,
root, send_data_tag, MPI_COMM_WORLD, &statusSlave);
for(int i = 0; i < numOfFilesForProcess; ++i)
{
fd = open (argv[firstFileIdForProcess + i], O_RDONLY);
if ( fd == -1
|| fstat (fd, &sb) == -1
|| !S_ISREG (sb.st_mode))
{
perror("file");
}
else
{
analyzeFile(sb, fd, argv[firstFileIdForProcess + i], pattern, proc_id);
}
}
}
MPI_Barrier(MPI_COMM_WORLD);
double endTime = MPI_Wtime();
if(proc_id == root)
{
printf("Czas wykonania: %fs\n", endTime - startTime);
}
MPI_Finalize();
return 0;
}

C program: Parent read one file and child count the number of words. Child have 4 Threads and mapper and reducer is also used

I am writing a C program in which I have a child and a parent. Parent and child share data using shared memory. What I am doing is asking parent to write the file in shared memory and child process then reads the file from shared memory and outputs a list showing the count of each unique word.
What I have to do is use 4 thread in child program and also use mapper and reducer to accomplish the task.
The text file is having around 30000 lines in it. My program is running correctly if I pass only 20000 lines in the text file but, now running for the whole file.
Please If someone can have a look at my program and let me know where I am going wrong will be surely appreciated.
Here is the link to the text file: http://cis-linux1.temple.edu/~qzeng/cis5512-fall2016/papers/ANNA_KARENINA.txt
And here is the code I am trying to run:
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <ctype.h>
#define NUM_THREADS 4
static key_t key = (key_t) 0;
static int size = 0;
struct thread_data
{
int thread_id;
char *msg;
char* wordary[10000][2];
int size;
};
struct thread_data thread_data_array[NUM_THREADS];
void *CountWords(void *threadarg)
{
int taskid, j, i=0, flag=0, index = 0, p, k,z, cnt, m;
char *msg_words, c, *word, buffer[8];
char* word_array[10000][2];
struct thread_data *my_data;
my_data = (struct thread_data *) threadarg;
taskid = my_data->thread_id;
msg_words = my_data->msg;
strcat(msg_words," ");
word = (char*) malloc(20);
word_array[0][0] = (char*) malloc(30);
word_array[0][1] = (char*) malloc(8);
FILE *out;
if(taskid==0)
out=fopen("out.txt","w");
//printf("%d\n", strlen(msg_words));
for(j=0; j < strlen(msg_words); j++)
{
c = msg_words[j];
c = tolower(c);
if(c == '\n')
{
c = ' ';
}
if(!isspace(c))
{
word[i++] = c;
}
if(c == '\0')
{
break;
}
if(c == ' ')
{
flag = 0;
for(k=0; k <= index; k++)
{
if(0 == strcmp(word_array[k][0],word))
{
flag = 1;
cnt = atoi(word_array[k][1]);
cnt++;
sprintf(buffer, "%d", cnt);
strcpy(word_array[k][1],buffer);
}
}
if(flag == 0)
{
strcpy(word_array[index][0],word);
strcpy(word_array[index][1],"1");
index++;
word_array[index][0]=(char*)malloc(30);
word_array[index][1]=(char*)malloc(8);
}
for(p=0; p <= 20; p++)
{
word[p] = 0;
}
i = 0;
//printf("%d",index);
}
//my_data->size = index;
}
printf("%d\n",index);
my_data->size = index;
for(m = 0; m<index; m++)
{
//printf("%d",m);
my_data->wordary[m][0] = (char*) malloc(30);
my_data->wordary[m][1] = (char*) malloc(8);
strcpy(my_data->wordary[m][0], word_array[m][0]);
strcpy(my_data->wordary[m][1], word_array[m][1]);
//printf("%s %s\n", my_data->wordary[m][0], my_data->wordary[m][1]);
}
pthread_exit((void *)my_data);
}
void main()
{
int ShmID, index = 0;
char* ShmPTR;
pid_t pid;
int status;
clock_t begin, end;
double time_spent;
begin = clock();
FILE *txtfile, *out_file;
txtfile = fopen("test.txt", "r");
fseek(txtfile, 0, SEEK_END); // seek to end of file
size = ftell(txtfile); // get current file pointer
fseek(txtfile, 0, SEEK_SET);
//printf("size : %d", size);
key = ftok(__FILE__,'x');
ShmID = shmget(key, size, IPC_CREAT | 0666);
if (ShmID < 0) {
printf("*** shmget error (server) ***\n");
exit(1);
}
printf("Server has received a shared memory\n");
ShmPTR = (char *) shmat(ShmID, NULL, 0);
if (ShmPTR == (char *)(-1)) {
printf("*** shmat error (server) ***\n");
exit(1);
}
printf("Server has attached the shared memory...\n");
while(!feof(txtfile))
{
ShmPTR[index] = fgetc(txtfile);
index++;
}
//ShmPTR[index] = '\0';
printf("Server is about to fork a child process...\n");
pid = fork();
if (pid < 0)
{
printf("*** fork error (server) ***\n");
exit(1);
}
else if (pid == 0)
{
printf(" Client process started\n");
//printf("%s",shm);
pthread_t threads[NUM_THREADS];
pthread_attr_t attr;
int rc, t, shmsz1, shmsz2, shmsz3;
char* split_ShmPTR[4];
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
//printf("1111");
//printf("%d\n",size);
shmsz1 = (int)(size/4);
shmsz2 = shmsz1*2;
shmsz3 = shmsz1*3;
// printf("%d %d %d\n", shmsz1, shmsz2, shmsz3);
//printf("%c\n",ShmPTR[87]);
while(ShmPTR[shmsz1] != ' ')
{
shmsz1++;
}
//printf("%d \n", shmsz1);
//printf("%c1\n",ShmPTR[shmsz1]);
split_ShmPTR[0] = (char*)malloc(shmsz1 + 1000);
strncpy(split_ShmPTR[0],ShmPTR,shmsz1);
while(ShmPTR[shmsz2] != ' ')
{
shmsz2++;
}
split_ShmPTR[1] = (char*)malloc(shmsz2-shmsz1 + 1000);
strncpy(split_ShmPTR[1],ShmPTR + shmsz1,shmsz2-shmsz1);
while(ShmPTR[shmsz3] != ' ')
{
shmsz3++;
}
split_ShmPTR[2] = (char*)malloc(shmsz3-shmsz2 + 1000);
strncpy(split_ShmPTR[2],ShmPTR + shmsz2,shmsz3-shmsz2);
split_ShmPTR[3] = (char*)malloc(size-shmsz3 + 10);
strncpy(split_ShmPTR[3],ShmPTR + shmsz3,size-shmsz3);
//printf("%s\n",split_ShmPTR[3]);
struct thread_data *my_words;
char* word_array_final[30000][2];
word_array_final[0][0] = (char*)malloc(30);
word_array_final[0][1] = (char*)malloc(8);
int q, r, flag1 = 0, count, idx = 0, z;
char buff[8];
for(t = 0; t<NUM_THREADS; t++)
{
thread_data_array[t].thread_id = t;
thread_data_array[t].msg = split_ShmPTR[t];
rc = pthread_create(&threads[t], NULL, CountWords, (void *) &thread_data_array[t]);
if (rc)
{
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
//pthread_join(threads[t],(void*)&my_words);
//printf("%d %s\n", my_words->thread_id, my_words->wordary[0][0]);
}
//pthread_exit(NULL);
//printf("%s\n", thread_data_array[3].msg);
pthread_attr_destroy(&attr);
for(t = 0; t<NUM_THREADS; t++)
{
pthread_join(threads[t],(void*)&my_words);
//printf("%d %s\n", my_words->thread_id, my_words->wordary[1][0]);
//printf("%d thread\n", t);
//printf("%d",my_words->size);
if(t == 0)
{
//printf("%d %s\n", my_words->thread_id, my_words->wordary[1][0]);
for(q = 0; q < my_words->size; q++)
{
strcpy(word_array_final[idx][0], my_words->wordary[q][0]);
strcpy(word_array_final[idx][1], my_words->wordary[q][1]);
idx++;
word_array_final[idx][0] = (char*)malloc(30);
word_array_final[idx][1] = (char*)malloc(8);
//printf("%s %s\n", word_array_final[idx][0], word_array_final[idx][1]);
}
}
else
{
//printf("%d %s %d\n", my_words->thread_id, my_words->wordary[1][0], my_words->size);
for(q = 0; q<my_words->size; q++)
{
flag1 = 0;
for(r = 0; r<idx; r++)
{
if(0 == (strcmp(word_array_final[r][0],my_words->wordary[q][0])))
{
flag1 = 1;
count = atoi(my_words->wordary[q][1]) + atoi(word_array_final[r][1]);
sprintf(buff, "%d", count);
strcpy(word_array_final[r][1],buff);
}
//printf("%s %s1\n", word_array_final[idx][0], word_array_final[idx][1]);
}
if(flag1 == 0)
{
strcpy(word_array_final[idx][0],my_words->wordary[q][0]);
strcpy(word_array_final[idx][1],my_words->wordary[q][1]);
idx++;
word_array_final[idx][0]=(char*)malloc(30);
word_array_final[idx][1]=(char*)malloc(8);
}
}
}
}
out_file=fopen("output.txt","w");
for(z=0; z<idx; z++)
{
fprintf(out_file, "%s : %s\n", word_array_final[z][1], word_array_final[z][0]);
}
printf("done");
fclose(out_file);
//pthread_exit(NULL);
printf(" Client is about to exit\n");
exit(0);
}
wait(&status);
printf("Server has detected the completion of its child...\n");
shmdt((void *) ShmPTR);
printf("Server has detached its shared memory...\n");
shmctl(ShmID, IPC_RMID, NULL);
printf("Server has removed its shared memory...\n");
printf("Server exits...\n");
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("Time spent: %lf\n", time_spent);
exit(0);
}
Please help me guys any help will be surely appreciated.
I found the solution...It a silly mistake...Size of my array was less...Now its fixed...And this program can be used as a child - parent program using shared memory also having mapper and reducers.

print garbage values from the shared memory

I am currently working on a producer-consumer implementation using C.
First, I create a buffer on the shared memory of a variable length that is given by the user in the consumer process.
Then, in the producer process, I need to access the shared memory and puts new data to the buffer so the consumer can consume.
Below is the consumer code:
#include "common.h"
#include <unistd.h>
int fd;
int errno;
int MY_LEN = 0;
Shared* shared_mem;
char *job[4];
int setup_shared_memory(){
fd = shm_open(MY_SHM, O_CREAT | O_RDWR, 0666);
if(fd == -1){
printf("shm_open() failed\n");
exit(1);
}
ftruncate(fd, sizeof(Shared) + MY_LEN*sizeof(char *));
}
int attach_shared_memory(){
shared_mem = (Shared*) mmap(NULL, sizeof(Shared) + MY_LEN*sizeof(char *), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(shared_mem == MAP_FAILED){
printf("mmap() failed\n");
exit(1);
}
return 0;
}
int init_shared_memory() {
shared_mem->data = 0;
int i;
for(i = 0; i < shared_mem->length; i++)
{
shared_mem->arr[i] = 0;
// shared_mem->arr[i] = (char *)calloc(1, sizeof(char*));
}
sem_init(&(shared_mem->mutex), 1, 1);
}
int init_job(){
int i;
for(i = 0; i < 4; i++)
{
job[i] = (char *)malloc(sizeof(char *));
}
}
int take_a_job(int index){
init_job();
char *ds = strdup(shared_mem->arr[index]);
job[0] = strtok(ds, "-");
int i = 1;
while(i < 4)
{
job[i] = strtok(NULL, "-");
i++;
}
// remove the job from the buffer
shared_mem->arr[index] = NULL;
}
int consume_job(int index){
printf("\nPrinter starts printing the job %s, %s pages from Buffer[%d]. The duration is %s seconds and the source is %s.\n",job[3], job[2], index, job[1], job[0]);
sleep(atoi(job[1])); // sleep for job[1] seconds.
}
int main(int args, char *argv[]) {
setup_shared_memory();
attach_shared_memory();
init_shared_memory();
MY_LEN = atoi(argv[1]); // the first parameter following ./printer = the length of the buffer
shared_mem->length = MY_LEN;
//shared_mem->arr = (int*) &shared_mem->arr;
int index = 1;
*(shared_mem->arr) = "1-10-5-6";
*(shared_mem->arr + 1) = "2-5-2-7";
*(shared_mem->arr + 2) = "3-20-10-8";
*(shared_mem->arr + 3) = "4-7-4-9";
take_a_job(index);
int i;
for(i = 0; i < shared_mem->length; i++){
printf("\n\n%d set %s\n", i, shared_mem->arr[i]);
}
consume_job(index);
printf("\n\nHello second check\n\n");
while (1) {}
return 0;
}
Here is the producer code:
#include "common.h"
int fd;
Shared* shared_mem;
char *job;
int setup_shared_memory(){
fd = shm_open(MY_SHM, O_RDWR, 0666);
if(fd == -1){
printf("shm_open() failed\n");
exit(1);
}
}
int attach_shared_memory(){
shared_mem = (Shared*) mmap(NULL, sizeof(Shared), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(shared_mem == MAP_FAILED){
printf("mmap() failed\n");
exit(1);
}
return 0;
}
int create_a_job(int args, char *argv[]){
int i;
job = (char *)calloc(8, sizeof(char *));
if(args != 5)
return 0; //the parameters are not correctly formatted
else{
for(i = 1; i < args; i++)
{
if(i > 1)
strcat(job, "-");
strcat(job, argv[i]);
}
}
strcat(job, "\0");
printf("\nthe job is %s\n", job);
}
int put_a_job(){
printf("shared_mem->length is %d\n\n", shared_mem->length);
int i;
for(i = 0; i < shared_mem->length; i++)
{
if(*(shared_mem->arr + i) == 0)
{
//shared_mem->arr[i] = (char *)malloc(sizeof(job));
//strcpy(shared_mem->arr[i], job);
*(shared_mem->arr + i) = (char *)job;
printf("\n\nThe index is %d\n", i);
//printf("\n\nthe argument is %s at %d\n", job, i);
return i;
}
}
printf("\n\nThe index is %d\n", i);
}
int main(int args, char *argv[]) {
setup_shared_memory();
attach_shared_memory();
// create a job with the parameters
int result = create_a_job(args, argv);
if(result == 0)
{
printf("Not the right parameters.\n");
printf("Plase enter client ID, job duration, number of pages and job ID.\n");
return 0;
}
int i;
put_a_job();
for (i=0; i < shared_mem->length; i++) {
printf("the argument is %s at %d\n", (char *)(shared_mem->arr + i), i);
}
printf("\n\n");
return 0;
}
The common.h file is
#ifndef _INCLUDE_COMMON_H_
#define _INCLUDE_COMMON_H_
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
// from `man shm_open`
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
#include <string.h>
#include <semaphore.h>
#define MY_SHM "/JIT"
typedef struct {
sem_t mutex;
int data;
int length; // the length of the buffer
char *arr[0];
} Shared;
#endif //_INCLUDE_COMMON_H_
I first run ./consumer 10 & to allocate a buffer of length 10 and after, I run ./producer 1 2 3 4 to put the job to the buffer and print the buffer, I got garbage values
Any help would be really appreciated! Thank you!
Instruction
*(shared_mem->arr + i) = (char *)job;
is storing the pointer job into the shared mem, not the pointed value.
Maybe you want to use a strncpy.
You cannot share memory address between processes, because of Linux uses virtual memory. To make the story short an address in a process is not valid for a different process.
Be aware that you have a memory leakage because you never call free() for the allocated job.

fork()- multiple files accessed by parent & child processes

For educational purposes, I wrote a program that forks a process and ...
the child continuously reads 3 files, prints the contents, sleeps for 10ms.
the parent keeps a counter for each file. each file also has a delay time associated with it.
each time a file's timer expires, the counter is incremented and the file is overwritten with the
new counter value. Each delay value is different, so all 3 files get updated at different rates.
The problem is, the counters only increment for a short time, and everything freezes after a few seconds. Can anyone give a good explanation of what is happening here?
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/time.h>
#define CHAN1WAIT 100000
#define CHAN2WAIT 750000
#define CHAN3WAIT 1000000
#define NCHAN 3
FILE *chanfiles[NCHAN] = {NULL, NULL, NULL}; //file pointers for fake 'devices'
char *filenames[NCHAN] = {"_chan1tmpfile_", "_chan2tmpfile_", "_chan3tmpfile_"};
int chanwait[NCHAN] = {CHAN1WAIT, CHAN2WAIT, CHAN3WAIT}; //time it takes for each 'device' to be updated with a new value
int chancount[NCHAN] = {0, 0, 0}; //value for each device
int clrcount = NCHAN * 8;
uint8_t chan1;
int read_chan (int chan)
{
char buf[4];
char c;
int i, ret;
short count = 0;
uint8_t set = 0;
char * retstr;
while (! set)
{
if (chanfiles[chan] == NULL) //if file is not in use
{
if ((chanfiles[chan] = fopen(filenames[chan], "r")) == NULL)
{
printf("Error opening file %s for reading.\n%s\n", filenames[chan], strerror(errno));
exit(-1);
}
while ((c = fgetc(chanfiles[chan])) != EOF)
{
buf[count] = c;
count++;
}
fclose(chanfiles[chan]);
chanfiles[chan] = NULL;
retstr = malloc(count + 1);
for (i = 0; i < count; i++) retstr[i] = buf[i];
ret = atoi(retstr);
free(retstr);
set = 1;
}
}
return ret;
}
void write_chan (int chan)
{
uint8_t set = 0;
while (! set)
{
if (chanfiles[chan] == NULL) //if file is not in use
{
if ((chanfiles[chan] = fopen(filenames[chan], "w")) == 0)
{
printf("Error opening file %s for writing.\n%s\n", filenames[chan], strerror(errno));
exit(-1);
}
if (fprintf(chanfiles[chan], "%d", chancount[chan]) < 0)
{
printf("Error writing to file %s:\n%s\n", filenames[chan], strerror(errno));
exit(-1);
}
fclose(chanfiles[chan]);
chanfiles[chan] = NULL;
set = 1;
}
}
}
time_t get_usecs()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec + tv.tv_usec;
}
int main (int argc, char * argv[])
{
pid_t pid;
time_t curtime;
int i;
for (i = 0; i < NCHAN; i++) write_chan(i);
printf("\nChannel:");
for (i = 0; i < NCHAN; i++) printf("%8d", i);
printf("\n Value:");
pid = fork();
// This process reads all 3 files, prints the values,
// then sleeps for 10ms, in an infinite loop.
if (pid == 0)
{
int j;
while (1)
{
uint8_t set;
for (j = 0; j < NCHAN; j++)
{
int value;
set = 0;
value = read_chan(j);
printf("%8d", value);
}
fflush(stdout);
usleep(10000);
for (j = 0; j < clrcount; j++) printf("\b"); fflush(stdout);
}
}
// This process updates the values of all 3 files at
// different rates, based on the value in chanwait[]
// for each file.
else
{
time_t timers[NCHAN];
int i;
for (i = 0; i < NCHAN; i++) timers[i] = get_usecs();
while (1)
{
for (i = 0; i < NCHAN; i++)
{
if ((get_usecs() - timers[i]) >= chanwait[i])
{
chancount[i]++;
write_chan(i);
timers[i] = get_usecs();
}
}
}
}
}
I am not sure this is your only problem, but your get_usecs function is suspect. You probably meant this
return tv.tv_sec * 1000000 + tv.tv_usec;
Rather than
return tv.tv_sec + tv.tv_usec;
Although, note that time_t is only guaranteed to be large enough for the time in seconds, not the number of microseconds as you have used it.

sem_init Segmentation fault error

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.

Resources