The following code is supposed to create one Producer thread and one Consumer thread. The Producer creates random numbers, adds them to a circular buffer(push_back()) and then writes them in an output txt called prod_out.txt. The Consumer "consumes" these numbers by poping them (pop_front()) and then writing them in an output txt called cons_out.txt. For a call like this ./a.out 1 1 10 20 1 the arguements are as follows: there will be 1 producer, 1 consumer, 10 is circular buffer's capacity, 20 random numbers will be generated and the seed for rand_r is 1.
If the buffer's capacity is smaller than the ammount of random nums to be generated the program only writes 9 numbers in the consumers' txt, while the producers' txt is just fine. If they are the same then the consumers' txt does not get created and producers' txt misses one number (namely the last one, just like the consumer txt does when the capacity is smaller than the numbers generated).
This is the main function
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include "prodcons.h"
FILE * fp;
int rc;
circular_buffer* cb;
int fileW, my_random;
pthread_mutex_t Mutex;
pthread_cond_t Condition;
args* t_args;
void* Producers(void* fargs){
printf("I am Producer and I am not locked\n");
args* f_args= fargs;
rc = pthread_mutex_lock(&Mutex);
printf("I am Producer and I am locked\n");
if (rc != 0) {
printf("ERROR: return code from pthread_mutex_lock() is %d\n", rc);
pthread_exit(&rc);
}
printf(" The ruler of all mutexes has passed from here and shall start
creating random numbers\n");
for(int i=0; i < *(f_args->rand_count); i++){
if(i==cb->capacity){
printf(" Your producer king will now sleep\n");
rc = pthread_cond_signal(&Condition);
if (rc != 0) {
printf("ERROR: return code from pthread_cond_signal() is %d\n",
rc);
pthread_exit(&rc);
}
rc = pthread_cond_wait(&Condition, &Mutex);
if (rc != 0) {
printf("ERROR: return code from pthread_cond_wait() is %d\n",
rc);
pthread_exit(&rc);
}
}
my_random =rand_r(f_args->seed)%255;
printf ( "Creating random number %d.\n", my_random);
cb_push_back(cb, &my_random);
if(i==0){
fp=fopen("prod_in.txt", "w");
}else{
fp=fopen("prod_in.txt", "a");
}
fprintf(fp, "Producer %d: %d\n", f_args->ID, my_random);
fclose(fp);
}
printf("I am going to go to signal the consumer.\n");
rc = pthread_cond_signal(&Condition);
if (rc != 0) {
printf("ERROR: return code from pthread_cond_signal() is %d\n", rc);
pthread_exit(&rc);
}
rc = pthread_mutex_unlock(&Mutex);
if (rc != 0) {
printf("ERROR: return code from pthread_mutex_unlock() is %d\n", rc);
pthread_exit(&rc);
}
}
void* Consumer(void* t1){
int *threadId = (int *) t1;
printf("I am Consumer and I am NOT locked\n");
rc = pthread_mutex_lock(&Mutex);
printf("I am Consumer and I am locked\n");
if (rc != 0) {
printf("ERROR: return code from pthread_mutex_lock() is %d\n", rc);
pthread_exit(&rc);
}
if(cb->count == 0){
rc = pthread_cond_wait(&Condition, &Mutex);
if (rc != 0) {
printf("ERROR: return code from pthread_cond_wait() is %d\n", rc);
pthread_exit(&rc);
}
}
int counter = cb-> count;
for (int j=0; j<= counter; j++){
printf("Consumer will now consume with items remaining %d.\n", (int)cb-
>count);
if(j==0){
fp=fopen("cons_out.txt", "w");
}else{
fp=fopen("cons_out.txt", "a");
}
printf("I will now write the following %d, %d inside the
file.\n",*threadId,my_random);
fprintf(fp, "Consumer %d: %d\n",*threadId, my_random);
cb_pop_front(cb,&my_random);
if(cb->count == 0){
rc = pthread_cond_signal(&Condition);
if (rc != 0) {
printf("ERROR: return code from pthread_cond_signal() is %d\n",
rc);
pthread_exit(&rc);
}
rc = pthread_cond_wait(&Condition, &Mutex);
if (rc != 0) {
printf("ERROR: return code from pthread_cond_wait() is %d\n",
rc);
pthread_exit(&rc);
}
}
fclose(fp);
}
rc = pthread_mutex_unlock(&Mutex);
if (rc != 0) {
printf("ERROR: return code from pthread_mutex_unlock() is %d\n", rc);
pthread_exit(&rc);
}
}
int main(int argc, char *argv[]){
if (argc !=6){
printf("ERROR: the program should take five arguments!\n");
exit(-1);
}
if(atoi(argv[1])!= 1 || atoi(argv[2])!= 1){
printf("ERROR:This program only functions for one producer and
consumer.\n");
exit(-1);
}
int main_seed = atoi(argv[5]);
int main_rand = atoi(argv[4]);
int buffer_size = atoi(argv[3]);
cb=(circular_buffer*) malloc(sizeof(struct circular_buffer));
t_args=(args*)malloc(sizeof(struct args));
cb_init(cb, buffer_size, sizeof(int));
t_args->seed= &main_seed;
t_args->rand_count= &main_rand;
t_args->ID=1;
int t1=1;
pthread_t p1, c1;
printf ( "I am the ruler of all mutexes. I now shall initialise the
mutex\n");
rc = pthread_mutex_init(&Mutex, NULL);
if (rc != 0) {
printf("ERROR: return code from pthread_mutex_init() is %d\n", rc);
exit(-1);
}
rc = pthread_cond_init(&Condition, NULL);
if (rc != 0) {
printf("ERROR: return code from pthread_cond_init() is %d\n", rc);
exit(-1);
}
rc = pthread_create(&p1, NULL, Producers, (void*)t_args); //cast σε void????
if (rc != 0) {
printf("ERROR: return code from pthread_create() is %d\n", rc);
exit(-1);
}
rc = pthread_create(&c1, NULL,Consumer, &t1);
if (rc != 0) {
printf("ERROR: return code from pthread_create() is %d\n", rc);
exit(-1);
}
void *status;
rc = pthread_join(p1, &status);
if (rc != 0) {
printf("ERROR: return code from pthread_join() is %d\n", rc);
exit(-1);
}
printf("Main(): Thread %d terminated successfully.\n", *(int *) status);
rc = pthread_join(c1, &status);
if (rc != 0) {
printf("ERROR: return code from pthread_join() is %d\n", rc);
exit(-1);
}
printf("Main(): Thread %d terminated successfully.\n", *(int *) status);
rc = pthread_mutex_destroy(&Mutex);
if (rc != 0) {
printf("ERROR: return code from pthread_mutex_destroy() is %d\n", rc);
exit(-1);
}
rc = pthread_cond_destroy(&Condition);
if (rc != 0) {
printf("ERROR: return code from pthread_cond_destroy() is %d\n", rc);
exit(-1);
}
free(cb);
free(t_args);
return 1;
}
This is a header file with the 2 structs and the circular buffer functions
#include "stdio.h"
#include "sys/types.h"
#include "stdlib.h"
#include "string.h"
typedef struct circular_buffer
{
void *buffer; // data buffer
void *buffer_end; // end of data buffer
size_t capacity; // maximum number of items in the buffer
size_t count; // number of items in the buffer
size_t sz; // size of each item in the buffer
void *head; // pointer to head
void *tail; // pointer to tail
}circular_buffer;
typedef struct args
{
int ID; //Unique ID from 1 to n
int* seed; //The seed used for rand_r
int* rand_count; //The number of random generated numbers
}args;
void cb_push_back(circular_buffer *cb, const void *item);
void cb_pop_front(circular_buffer *cb, void *item);
void cb_init(circular_buffer *cb, size_t capacity, size_t sz);
void cb_free(circular_buffer *cb);
In this file are the implementetions of the circular buffer functions
#include "prodcons.h"
//initialize circular buffer
//capacity: maximum number of elements in the buffer
//sz: size of each element
void cb_init(circular_buffer *cb, size_t capacity, size_t sz)
{
cb->buffer = malloc(capacity * sz);
if(cb->buffer == NULL){
printf("Could not allocate memory..Exiting! \n");
exit(1);
}
// handle error
cb->buffer_end = (char *)cb->buffer + capacity * sz;
cb->capacity = capacity;
cb->count = 0;
cb->sz = sz;
cb->head = cb->buffer;
cb->tail = cb->buffer;
}
//destroy circular buffer
void cb_free(circular_buffer *cb)
{
free(cb->buffer);
// clear out other fields too, just to be safe
}
//add item to circular buffer
void cb_push_back(circular_buffer *cb, const void *item)
{
if(cb->count == cb->capacity)
{
printf("Access violation. Buffer is full\n");
exit(1);
}
memcpy(cb->head, item, cb->sz);
cb->head = (char*)cb->head + cb->sz;
if(cb->head == cb->buffer_end)
cb->head = cb->buffer;
cb->count++;
}
//remove first item from circular item
void cb_pop_front(circular_buffer *cb, void *item)
{
if(cb->count == 0)
{
printf("Access violation. Buffer is empy\n");
exit(1);
}
memcpy(item, cb->tail, cb->sz);
cb->tail = (char*)cb->tail + cb->sz;
if(cb->tail == cb->buffer_end)
cb->tail = cb->buffer;
cb->count--;
}
Related
I need to create two private keys and two threads and then I need to make these threads "exchange" keys
I already created the keys and initialized them and I can also print their value, but I do not know how to make them exchange keys. Maybe someone will tell you something. maybe for this I need to call the same thread several times, but I also don’t know how to do this. I do not ask you to give me a ready-made program, maybe just some little hint or advice
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
pthread_key_t key, key2;
void get_data()
{
int *x = (int*)pthread_getspecific(key2);
if(x == NULL)
printf("The value is NULL\n");
else
printf("Key value is %d\n", *x);
}
void get_data2()
{
int *x = (int*)pthread_getspecific(key);
if(x == NULL)
printf("The value is NULL\n");
else
printf("Key value is %d\n", *x);
}
void *func(void *data)
{
int *num;
int *x;
printf("Thread №%ld\n", pthread_self());
num = (int*)data;
get_data();
pthread_setspecific(key, (void*)num);
get_data();
}
void *func2(void *data)
{
int *num;
int *x;
printf("Thread №%ld\n", pthread_self());
num = (int*)data;
get_data2();
pthread_setspecific(key2, (void*)num);
get_data2();
}
int main()
{
int ret_code, type = 3;
pthread_t th, th2;
ret_code = pthread_key_create(&key, NULL);
if(ret_code != 0)
fprintf(stderr, "ptrhead_key_create() error %d\n", ret_code);
ret_code = pthread_key_create(&key2, NULL);
if(ret_code != 0)
fprintf(stderr, "ptrhead_key_create() error %d\n", ret_code);
printf("type: %d\n", type);
ret_code = pthread_create(&th, NULL, func, (void*)&type);
if(ret_code != 0)
fprintf(stderr, "pthread_create() error %d\n", ret_code);
sleep(1);
type = 10;
printf("type: %d\n", type);
ret_code = pthread_create(&th2, NULL, func2, (void*)&type);
if(ret_code != 0)
fprintf(stderr, "pthread_create() error %d\n", ret_code);
ret_code = pthread_join(th, NULL);
ret_code = pthread_join(th2, NULL);
}
This function is executed by a thread. I believe the error occurs when I try to access rand_count which, is a variable of the struct called args. Note that the problem is located in the for loop of the producer.
void* Producers(void* fargs) {
printf("I am Producer and I am not locked\n");
args* f_args=(args*) fargs;
rc = pthread_mutex_lock(&Mutex);
printf("I am Producer and I am locked\n");
if (rc != 0) {
printf("ERROR: return code from pthread_mutex_lock() is %d\n", rc);
pthread_exit(&rc);
}
printf(" The ruler of all mutexes has passed from here and shall start creating random numbers\n");
for(int i=0; i < *f_args->rand_count; ++i) {
printf ( "Creating random number\n");
my_random =rand_r(f_args->seed)%255;
if(i==cb->capacity) {
printf(" Your producer king will now sleep\n");
rc = pthread_cond_signal(&Condition);
if (rc != 0) {
printf("ERROR: return code from pthread_cond_signal() is %d\n", rc);
pthread_exit(&rc);
}
rc = pthread_cond_wait(&Condition, &Mutex);
if (rc != 0) {
printf("ERROR: return code from pthread_cond_wait() is %d\n", rc);
pthread_exit(&rc);
}
}
cb_push_back(cb, &my_random);
if(i==0) {
fp=fopen("prod_in.txt", "w");
} else {
fp=fopen("prod_in.txt", "a");
}
fprintf(fp, "Producer %d: %d\n", f_args->ID, my_random);
}
rc = pthread_cond_signal(&Condition);
if (rc != 0) {
printf("ERROR: return code from pthread_cond_signal() is %d\n", rc);
pthread_exit(&rc);
}
rc = pthread_mutex_unlock(&Mutex);
if (rc != 0) {
printf("ERROR: return code from pthread_mutex_unlock() is %d\n", rc);
pthread_exit(&rc);
}
}
This is the struct
typedef struct args{
int ID; //Unique ID from 1 to n
int* seed; //The seed used for rand_r
int* rand_count; //The number of random generated numbers
}args;
Im working on a project that is mainly producer-consumer with pthread conditions and mutexes on a circular buffer. The user gives how many consumers and producer threads it wants, random number generator seed, how many numbers each producer produces and the size of the circular buffer. All of them along with the condition and the mutex are global variables
Here is the producer thread code
void * newProducer(void * t){
// Get the thread id
int * a = (int *) t;
int id = *a;
printf("Producer thread %d started!\n", id);
int i;
//Get the seed
//seed is global vairable(Random number generator seed
unsigned int thread_seed = seed * id;
//Allocate memory for the array to save the numbers
int * numbers = (int *) malloc(sizeof(int) * n);
//Open the files
FILE * producer_file = fopen("prods_out.txt", "w");
if(producer_file == NULL){
printf("ERROR: fopen failed.\n");
exit(1);
}
fprintf(producer_file, "-- PRODUCER DATA --\n");
//Produce the numbers
for( i = 0; i < n; i++){
numbers[i] = rand_r(&thread_seed) % 100;
//Lock mutex
if(pthread_mutex_lock(&mutex) < 0){
printf("ERROR: pthread_mutex_lock failed.\n");
exit(1);
}
//printf("Producer thread <%d> locked mutex\n", *id);
//Wait until the cb has space to store numbers
while(cb->count == cb->capacity) {
if(pthread_cond_wait(&cond, &mutex) < 0){
printf("ERROR: pthread_cond_wait failed\n");
exit(1);
}
printf("Producer <%d> waiting\n", id);
}
//Put the number in the cb
cb_push_back(cb, &numbers[i]);
// printf("Producer <%d>: %d\n", id, numbers[i]);
fprintf(producer_file, "Producer <%d>: %d\n", id, numbers[i]);
count++;
//Count is a global variable to inform the consumers that there're
//no more numbers to be produced
//Tell the consumer threads that you have put a number to the cb
if(pthread_cond_broadcast(&cond) < 0){
printf("ERROR: pthread_cond_broadcast failed.\n");
exit(1);
}
//Unlock the mutex
if(pthread_mutex_unlock(&mutex) < 0){
printf("ERROR: pthread_mutex_unlock failed\n");
exit(1);
}
//printf("Producer thread <%d> unlocked mutex\n", *id);
}
// Free array
free(numbers);
//Close File
fprintf(producer_file, "-- END DATA --");
if( fclose(producer_file) != 0){
printf("ERROR: fclose failed.\n");
exit(1);
}
//THREAD EXIT
printf("PRODUCER %d EXITS\n", id);
pthread_exit(t);
}
And here is the consumer thread
void * newConsumer(void * t){
// Get the thread id
int * a = (int*) t;
int id = *a;
printf("Consumer thread %d started!\n", id);
int number;
//Open the file
FILE * consumer_file = fopen("cons_out.txt", "w");
if(consumer_file == NULL){
printf("ERROR: fopen failed.\n");
exit(1);
}
fprintf(consumer_file, "-- CONSUMER DATA --\n");
/*Consume integers until there are no integers left
either to be produced or in the buffer waiting */
while(count != p*n || cb->count != 0){
//Lock the mutex
//printf("Consumer <%d> has locked the mutex\n", *id);
if (pthread_mutex_lock(&mutex) < 0){
printf("ERROR: Could not lock mutex\n");
exit(1);
}
//Wait until a producer puts an integer in the cb
while(cb->count == 0 && end == 0){
printf("Consumer <%d> waiting\n", id);
if(pthread_cond_wait(&cond, &mutex) < 0){
printf("ERROR: pthread_cond_wait failed.\n");
exit(1);
}
}
if (cb->count != 0){
//Consume a number
cb_pop_front(cb, &number);
// printf("Consumer <%d>: %d\n", id, number);
fprintf(consumer_file, "Consumer <%d>: %d\n", id, number);
}
//Tell the producers that you have popped a number from the cb
if(pthread_cond_broadcast(&cond) < 0){
printf("ERROR: pthread_cond_broadcast() failed.\n");
exit(1);
}
//printf("Consumer <%d> Broadcast.\n", id);
//Unlock the mutex
//printf("Consumer <%d> has unlocked the mutex\n", *id);
if(pthread_mutex_unlock(&mutex) < 0){
printf("ERROR: pthread_mutex_unlock failed\n");
exit(1);
}
}
//Close the file stream
fprintf(consumer_file, "-- END DATA --");
if(fclose(consumer_file) != 0){
printf("ERROR: fclose failed.\n");
exit(1);
}
// THREAD EXIT
printf("CONSUMER %d EXITS\n", id);
pthread_exit(t);
}
In the main function i run
pthread_t * CONSUMERS[i] = (pthread_t*) malloc(sizeof(pthread_t) * i);
if (CONSUMERS == NULL){
printf("ERROR: Malloc failed.\n");
exit(1);
}
for (i = 0; i<c; i++){
id[i] = i+1;
pthread_create(&CONSUMERS[i], NULL, newConsumer, &id[i]);
}
and the I wait for them to finish.
i do exactly the same for the producer threads.( With a diffrent pthread_t array and id array.)
So the thing is : the id I put at the args at create is getting changed. If I run 5 consumer threads even though I put their id as 1 , 2, 3, 4, 5 it comes out as 65, 2, 3, 4, 68. This happens to the producer threads as well.
Thanks.
I have a program that is supposed to copy the contents of a file exactly to another file using multiple threads. The reader thread reads a line from the file and stores it in a circular buffer. The writer thread then reads from the buffer and writes to the file. However I am getting a segmentation fault and it is not writing to the file. Any idea why I am getting a segmentation fault or is there any way that I can find out what is causing the error?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
FILE *inputFile;
FILE *outputFile;
pthread_mutex_t mutex;
int endOfFile = 0;
typedef struct bufferStruct{
int capacity;
int size;
int head;
int tail;
char **data;
}buffer;
buffer * bufferInit(int maxElements){
buffer *buf;
buf = (buffer *)malloc(sizeof(buffer));
buf->data = (char**)malloc(sizeof(char*)*maxElements);
buf->size = 0;
buf->capacity = maxElements;
buf->head = 0;
buf->tail = -1;
return buf;
}
void popFront(buffer *buf){
if(buf->size != 0){
free(buf->data);
buf->size--;
buf->head++;
if(buf->head == buf->capacity){
buf->head = 0;
}
}
return;
}
char* front(buffer *buf){
if(buf->size != 0){
return buf->data[buf->head];
}
return NULL;
}
void pushBack(buffer *buf, char *data){
if(buf->size == buf->capacity){
printf("Queue is Full\n");
}
else{
buf->size++;
buf->tail = buf->tail + 1;
if(buf->tail == buf->capacity){
buf->tail = 0;
}
buf->data[buf->tail] = (char *) malloc((sizeof data + 1)* sizeof(char));
strcpy(buf->data[buf->tail], data);
}
return;
}
buffer *buf;
void* reader(void* arg){
char line[1024];
while(endOfFile != 1){
fgets(line, sizeof(line), inputFile);
printf("Line read: %s", line);
pushBack(buf, line);
if(feof(inputFile)){
endOfFile = 1;
}
}
pthread_exit(0);
}
void* writer(void* arg){
char *line;
while(endOfFile != 1){
pthread_mutex_lock(&mutex);
line = front(buf);
fputs(line, outputFile);
popFront(buf);
pthread_mutex_unlock(&mutex);
}
pthread_exit(0);
}
int main(int argc, char **argv){
if (argc < 4) {
printf("Usage: %s <input file> <output file> <number>\n", argv[0]);
exit(-1);
}
inputFile = fopen(argv[1], "r");
outputFile = fopen(argv[2], "w");
int numOfThreads = atoi(argv[3]);
buf = bufferInit(16);
pthread_t readerTids[numOfThreads];
pthread_t writerTids[numOfThreads];
pthread_mutex_init(&mutex, NULL);
for(int i = 0; i < numOfThreads; i++){
if(endOfFile != 1){
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&readerTids[i], &attr, reader, NULL);
pthread_create(&writerTids[i], &attr, writer, NULL);
printf("Thread %d created\n", i);
}
}
for (int i = 0; i < numOfThreads; i++) {
pthread_join(readerTids[i], NULL);
pthread_join(writerTids[i], NULL);
}
fclose(inputFile);
fclose(outputFile);
}
Consider the possibility of your reader thread being slower than the writer thread. The writer thread alone holds the lock, does the locking and unlocking, not being bothered about the reader. What if the writer tries to use the buffer when reader hasn't updated the buffer yet? Use thread synchronisation, say semaphores, which does not have any ownership issues.
void* reader(void* arg){
char line[1024];
while(endOfFile != 1){
fgets(line, sizeof(line), inputFile);
printf("Line read: %s", line);
pushBack(buf, line);
--- Lock semaphore here---
if(feof(inputFile)){
endOfFile = 1;
}
}
pthread_exit(0);
}
void* writer(void* arg){
char *line;
while(endOfFile != 1){
-- Unlock semaphore here---
line = front(buf);
fputs(line, outputFile);
popFront(buf);
}
pthread_exit(0);
}
Unlike mutex, the same semaphore can be used between both threads. This helps you to sync up both threads.
I can't exit or terminate children processes sending a signal.
Could you please tell me what I'm doing wrong in this code:
//###################################### INVERTER.C (main)
#include <semaphore.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <errno.h>
#include <unistd.h>
#include "timeprofiler.h"
#include "ppmtools.h"
//Global vars:
int shmids[4], shmPixelId, *total_lines, *processed_lines, *next_line, *buf_vars;
//To share unnamed semaphores between processes, they must be allocated in a shared memory.
mem_struct *sh_mm;
//unnamed semaphores
sem_t *mutex1, *mutex2, *mutex3, *sem_remaining_lines;
//struct that will hold the image in shared memory
image_struct *image;
pid_t *workersPID;
header *h;
int main(int argc, char *argv[]) {
int i, j, k, cur = 0, id;
pixel *row;
double start, stop, startms, stopms;
if (argc < 3) {
printf("Incorrect usage.\nPlease use \"./invert input_filename.ppm output_filename.ppm\"\n");
return -1;
}
//BLOCK ALL SIGNAL
sigset_t block_ctrlc;
sigfillset(&block_ctrlc);
sigdelset(&block_ctrlc, SIGINT);
sigprocmask(SIG_BLOCK, &block_ctrlc, NULL);
//start timer
start = getCurrentTimeMicro();
startms = getCurrentTimeMili();
printf("Opening input file [%s]\n", argv[1]);
FILE *fpin = fopen(argv[1], "r");
if (fpin == NULL) {
printf("Could not open input file\n");
return -1;
}
printf("Opening output file [%s]\n", argv[2]);
FILE *fpout = fopen(argv[2], "w");
if (fpout == NULL) {
printf("Could not open output file\n");
return -1;
}
printf("Getting header\n");
h = getImageHeader(fpin);
if (h == NULL) {
printf("Error getting header from file\n");
return -1;
}
printf("Got file Header: %s - %u x %u - %u\n", h->type, h->width, h->height, h->depth);
printf("Saving header to output file\n");
if (writeImageHeader(h, fpout) == -1) {
printf("Could not write to output file\n");
return -1;
}
init();
printf("After init...\n");
//alloc mem space for one row (width * size of one pixel struct)
row = (pixel *) malloc(h->width * sizeof (pixel));
printf("Starting work\n");
for (i = 0; i < h->height; i++) {
printf("Reading row... \n");
if (getImageRow(h->width, row, fpin) == -1) {
printf("Error while reading row\n");
}
printf("Got row %d || \n", (i + 1));
for (j = cur, k = 0; j < cur + h->width; j++, k++) {
image->pixel_data[j].red = row[k].red;
image->pixel_data[j].blue = row[k].blue;
image->pixel_data[j].green = row[k].green;
}
cur += h->width;
}
/*Creates workers*/
workersPID = (pid_t*) malloc(sizeof (pid_t) *((NUM_WORKERS)));
for (i = 0; i < NUM_WORKERS; i++) {
id = fork();
if (id == -1) {
printf("Error creating worker no %d\n", i);
return (EXIT_FAILURE);
} else if (id == 0) {
workersPID[i] = getpid();
printf("Launching son with pid %d\n", getpid());
worker(i);
}
}
cur = 0;
sem_wait(mutex2);
/*Writes the invert image on the output file*/
for (i = 0; i < h->height; i++) {
for (j = cur, k = 0; j < cur + h->width; j++, k++) {
row[k].red = image->pixel_data[j].red;
row[k].blue = image->pixel_data[j].blue;
row[k].green = image->pixel_data[j].green;
}
cur += h->width;
printf("Saving row... \n");
if (writeRow(h->width, row, fpout) == -1) {
printf("Error while writing row\n");
}
printf("Done\n");
}
printf("Cleaning up...\n");
//clean up row
free(row);
//clean up header
free(h);
printf("Closing file pointers.\n");
fclose(fpin);
fclose(fpout);
//stop timer
stop = getCurrentTimeMicro();
stopms = getCurrentTimeMili();
for (i = 0; i < NUM_WORKERS; i++) {
if (workersPID[i]) {
kill(workersPID[i], SIGTERM);
waitpid(workersPID[i], NULL, 0);
}
}
terminate();
printTimeElapsed(start, stop, "microseconds");
printTimeElapsed(startms, stopms, "miliseconds");
printf("Done!\n");
return 0;
}
void init() {
//create shared memory to hold the source image:
if ((shmids[0] = shmget(IPC_PRIVATE, sizeof (image_struct), IPC_CREAT | 0700)) == -1) {
printf("shmget to allocate image struct failed. Errno returned: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
image = (image_struct*) shmat(shmids[0], NULL, 0);
//shared memory to allocate the pointer to pointer pixel_data
if ((shmids[1] = shmget(IPC_PRIVATE, h->width * h->height * sizeof (pixel), IPC_CREAT | 0700)) == -1) {
printf("shmget to allocate pixel_data array failed. Errno returned: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
image->pixel_data = (pixel*) shmat(shmids[1], NULL, 0);
/*Shared Memory segment for 3 integers*/
if ((shmids[2] = shmget(IPC_PRIVATE, 3 * sizeof (int), IPC_CREAT | 0700)) == -1) {
printf("shmget to allocate the 3 integers failed. Errno returned; %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
buf_vars = (int*) shmat(shmids[2], NULL, 0);
total_lines = &buf_vars[0];
processed_lines = &buf_vars[1];
next_line = &buf_vars[2];
*processed_lines = *next_line = 0;
*total_lines = h->height;
if ((shmids[3] = shmget(IPC_PRIVATE, sizeof (mem_struct), IPC_CREAT | 0700)) == -1) {
printf("shmget to allocate mem_Struct for semaphores failed. Errno returned %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
sh_mm = (mem_struct*) shmat(shmids[3], NULL, 0);
if (sem_init(&sh_mm->mutex1, 1, 1) == -1) {
printf("Error initializing semaphore mutex1.Errno returned: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
mutex1 = &sh_mm->mutex1;
if (sem_init(&sh_mm->mutex2, 1, 0) == -1) {
printf("Error initializing semaphore mutex2.Errno returned: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
mutex2 = &sh_mm->mutex2;
if (sem_init(&sh_mm->mutex3, 1, 1) == -1) {
printf("Error initializing semaphore mutex3.Errno returned: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
mutex3 = &sh_mm->mutex3;
if (sem_init(&sh_mm->sem_remaining_lines, 1, h->height) == -1) {
printf("Error initializing semaphore sem_remaining_lines.Errno returned: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
sem_remaining_lines = &sh_mm->sem_remaining_lines;
}
/*Worker process*/
void worker(int id) {
int i, k, cur = 0;
pixel *row;
//Block all signals, except SIGINT and SIGKILL which are handled
sigset_t block_ctrlc;
sigfillset(&block_ctrlc);
sigdelset(&block_ctrlc, SIGINT);
sigdelset(&block_ctrlc, SIGTERM);
sigprocmask(SIG_BLOCK, &block_ctrlc, NULL);
signal(SIGINT, handle_signal);
signal(SIGTERM, handle_signal);
while (sem_wait(sem_remaining_lines)!= -1) { //if there are still lines to read, go on
sem_wait(mutex3);
cur = *next_line; //current image's line
*next_line += h->width; //refreshs line for the next worker
sem_post(mutex3);
row = (pixel *) malloc(h->width * sizeof (pixel));
for (i = cur, k = 0; i < cur + h->width; i++, k++) {
row[k].red = image->pixel_data[i].red;
row[k].blue = image->pixel_data[i].blue;
row[k].green = image->pixel_data[i].green;
}
//printf("% - Inverting row... \n",id);
invertRow(h->width, row); //invert
//printf("Done || \n");
for (i = cur, k = 0; i < cur + h->width; i++, k++) {
image->pixel_data[i].red = row[k].red;
image->pixel_data[i].blue = row[k].blue;
image->pixel_data[i].green = row[k].green;
}
sem_wait(mutex1);
*processed_lines += 1; //increases the number of inverted lines
if (*processed_lines == *total_lines) { //check if it reaches last line
sem_post(mutex2); //if so, wakes the master telling that is ready
}
sem_post(mutex1);
}
//printf("Son %d is exiting\n",id);
exit(0);
}
void handle_signal(int signum) {
if(signum == SIGINT)
signal(SIGINT, handle_signal);
else
signal(SIGTERM, handle_signal);
exit(0);
}
void terminate() {
int i;
//close semaphores
sem_destroy(mutex1);
sem_destroy(mutex2);
sem_destroy(mutex3);
sem_destroy(sem_remaining_lines);
//cleans up shared memory = removes shared memory segments
for (i = 0; i < 4; i++) {
shmctl(shmids[i], IPC_RMID, NULL);
}
}
I'm gonna leave the explanation of the assignment (that has already finished btw)here:
1 page pdf
Your worker threads have SIGTERM blocked (because it was blocked in main, and sigprocmask doesn't remove signals from the blocked set unless explicitly told to do so)
You may want to do something like this in the worker instead:
sigemptyset(&block_ctrlc);
sigaddset(&block_ctrlc, SIGINT);
sigaddset(&block_ctrlc, SIGTERM);
sigprocmask(SIG_UNBLOCK, &block_ctrlc, NULL);
Alternately, call sigprocmask with SIG_SETMASK.