Producer and consumer with semaphores, multiple pthreads, 2 buffers - c

OK. So I have 2 buffers, implemented as heap. It has an init, insert, and delete function. The priority in this case does not matter though.
For each buffer, there are 3 producer threads producing an item (letter) and inserting it into a buffer. Three producers for a buffer holding uppercase letters, and three for a buffer holding lowercase letters. Obviously only 1 producer may append at a time to a buffer.
There are 10 consumer threads. These threads can access either buffer, but only up to 3 at a time per buffer, and not when a producer is producing. I am trying to instruct the threads to go first to the buffer with more items in it, then the other.
My problem is with deadlocks I believe. I am getting segmentation faults, so I assume that my semaphores are not working correctly (I have not implemented them correctly).
I first worked on this problem using a single buffer, with multiple consumers/producers and was able to get it to work. I have basically segmented the 1 buffer solution into multiple parts.
I'm using 3 semaphores for each buffer. A mutex, so only 1 item can take or append something per buffer. These are named mutex and mutex2. emptycount and fillcount are the counting sems used that start at the max_buffer_size and 0 respectively.
The consumers must take a letter from each buffer before consuming. The order in which they do this is not important, so I'm trying to tell each one to take something from the buffer with more in it first, then the other buffer. I've put a semaphore starting at 3 outside of the consumer code for each buffer. These are sems upper and lower, and are used to make sure only 3 consumers can enter any one buffer at a time.
Variables countUpper and countLower are supposed to count how many items are in each buffer at the time.
I'm sure my sems are placed incorrectly but i cannot find out where, I'm very new to threading. The queues are abstracted and in another file, but they work correctly. Also, I'm only producing lowercase letters atm, but that shouldn't matter.
Any help is appreciated.
#include "pq.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <semaphore.h>
#include <pthread.h>
#define MAX_CPRODUCER 3
#define MAX_LPRODUCER 3
#define MAX_CONSUMER 10
#define MAX_INT 2147483647
// Is the structure for the items produced by the producer thread
typedef struct product product_t;
struct product {
char item;
int PrdPID;
unsigned int sequence_num;
};
typedef struct pq_struct pq_struct_t;
struct pq_struct
{
pq_t lower;
pq_t upper;
};
int countUpper, countLower;
sem_t mutex, fillCount, emptyCount;
sem_t mutex2, fillCount2, emptyCount2;
sem_t lower, upper;
//Produce a letter to put in
product_t *produce(int pid, unsigned int count)
{
product_t *aProduct = malloc( sizeof(*aProduct) );
aProduct->item = (char)(rand() % 26 + 97); //To get ascii lowercase
aProduct->PrdPID = pid;
aProduct->sequence_num = count;
return aProduct;
}
//Append the letter to the buffer
void append(void *pq, product_t *aProduct)
{
//Insert letter into queue
//Key is irrelevant and always 1 for this program
pq_insert((pq_t*)pq, 1, (void*)aProduct);
//printf("Appended: ID = %d Count = %d Letter = %c\n", aProduct->PrdPID, aProduct->sequence_num, aProduct->item);
}
//Take a letter from buffer
product_t *take(void *pq)
{
//Delete from buffer and place in our consumer product
product_t *aProduct = (product_t*)pq_delete((pq_t*)pq);
return aProduct;
}
//Consume the letter
void consume(product_t *aProduct, product_t *theProduct, int id)
{
printf("Removing: ID = %d Count = %d Letter = %c\n", aProduct->PrdPID, aProduct->sequence_num, aProduct->item);
free(aProduct); //Takes place of consume
free(theProduct);
}
//Producer function for uppercase buffer
void *ProducerCapital (void *pq)
{
pq_t *upperPq = pq;
product_t *cProduct = NULL;
unsigned int count = 0;
for (;;)
{
cProduct = produce(1, ++count);
sem_wait(&emptyCount);
sem_wait(&mutex);
//Make new item
append(upperPq, cProduct);
++countUpper;
//
sem_post(&mutex);
sem_post(&fillCount);
}
pthread_exit (NULL);
}
//Producer thread for lowercase buffer
void *ProducerLower (void *pq)
{
pq_t *lowerPq = pq;
product_t *lProduct = NULL;
unsigned int count = 0;
for (;;)
{
lProduct = produce(1, ++count);
sem_wait(&emptyCount2);
sem_wait(&mutex2);
//Make new item
append(lowerPq, lProduct);
++countLower;
//
sem_post(&mutex2);
sem_post(&fillCount2);
}
pthread_exit (NULL);
}
void ConsumeUpper(pq_t *pqUpper, product_t *capProd)
{
sem_wait(&fillCount);
sem_wait(&mutex);
//Take Item
capProd = (product_t*)take((void*)pqUpper);
//
sem_post(&mutex);
sem_post(&emptyCount);
}
void ConsumeLower(pq_t *pqLower, product_t *lowProd)
{
sem_wait(&fillCount2);
sem_wait(&mutex2);
//Take Item
lowProd = (product_t*)take((void*)pqLower);
//
sem_post(&mutex2);
sem_post(&emptyCount2);
}
void *Consumer (void *pq)
{
pq_struct_t *sharePqs = (pq_struct_t*)pq;
product_t *capitalProduct = NULL;
product_t *lowerProduct = NULL;
for (;;)
{
if(countUpper < countLower)
{
sem_wait(&lower);
--countLower;
ConsumeLower(&sharePqs->lower, capitalProduct);
sem_post(&lower);
sem_wait(&upper);
--countUpper;
ConsumeUpper(&sharePqs->upper, capitalProduct);
sem_post(&upper);
}
else
{
sem_wait(&upper);
--countUpper;
ConsumeUpper(&sharePqs->upper, capitalProduct);
sem_post(&upper);
sem_wait(&lower);
--countLower;
ConsumeLower(&sharePqs->lower, capitalProduct);
sem_post(&lower);
}
consume(capitalProduct, lowerProduct , 2);
}
pthread_exit (NULL);
}
int main ()
{
//Create queue
pq_struct_t my_pqs;
//Initialize the queue
pq_init(&my_pqs.upper);
pq_init(&my_pqs.lower);
pthread_t cProducers[MAX_CPRODUCER];
pthread_t lProducers[MAX_LPRODUCER];
pthread_t consumers[MAX_CONSUMER];
srand(time(NULL)); // randomize random function call
int i, code;
countUpper = 0;
countLower = 0;
sem_init(&mutex, 0, 1);
sem_init(&fillCount, 0, 0);
sem_init(&emptyCount, 0, MAX_INT);
sem_init(&mutex2, 0, 1);
sem_init(&fillCount2, 0, 0);
sem_init(&emptyCount2, 0, MAX_INT);
sem_init(&lower, 0, 3);
sem_init(&upper, 0, 3);
for (i=0; i<MAX_CONSUMER; ++i)
{
printf ("In main: creating consumer thread %d\n", i);
code = pthread_create(&consumers[i], NULL, Consumer, (void *)&my_pqs);
if (code)
{
printf ("Error: pthread_create: %d\n", code);
exit (-1);
}
}
for (i=0; i<MAX_CPRODUCER; ++i)
{
printf ("In main: creating producer thread %d\n", i);
code = pthread_create(&cProducers[i], NULL, ProducerCapital, (void *)&my_pqs.upper);
if (code)
{
printf ("Error: pthread_create: %d\n", code);
exit (-1);
}
}
for (i=0; i<MAX_LPRODUCER; ++i)
{
printf ("In main: creating producer thread %d\n", i);
code = pthread_create(&lProducers[i], NULL, ProducerLower, (void *)&my_pqs.lower);
if (code)
{
printf ("Error: pthread_create: %d\n", code);
exit (-1);
}
}
pthread_exit (NULL);
}

Related

Use mutex cause deadlock in c

Im trying to make a mini threads game, should be a manager thread that create amount of thread as the user want, and for every round (the user choose the amount of rounds) the threads need to random number, and after all the threads finished to random number the managerGame thread should print the thread that random the greatest number and add point to this thread.
At the end of the game the ManagerGame thread should print who is the winner.
Now i wrote the next code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
struct Player{
int isFinished;
int id;
int number;
};
struct GameManager{
struct Player *Players;
int *WinnersTable;
int Rounds;
};
struct GameDetails{
int PlayersCount;
int RoundsCount;
};
struct GameManager game_manager;
pthread_mutex_t lock;
pthread_cond_t cond;
int IsGameActive;
void* ManagerGameFunc(void* gameDetails);
void* PlayerFunc(void* playerDetails);
void SetWinnerToRound(int roundNumber, int playersCount);
void StartNewRound(int playersCount);
void printWinnerToGame(int playersCount);
int IsRoundEnded(int playersCount);
int main(){
srand(time(NULL));
pthread_t ManagerThread;
pthread_mutex_init(&lock, NULL);
pthread_cond_init(&cond, NULL);
struct GameDetails gameDetails;
printf("----GAME----\n");
printf("Enter amount of players\n");
fflush(stdin);
scanf("%d\n", &gameDetails.PlayersCount);
printf("Enter amount of rounds\n");
fflush(stdin);
scanf("%d\n", &gameDetails.RoundsCount);
printf("----GAME STARTED----\n");
pthread_create(&ManagerThread, NULL, ManagerGameFunc, &gameDetails);
pthread_join(ManagerThread, NULL);
printf("Game finished\n");
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&cond);
}
void* ManagerGameFunc(void* gameDetails){
struct GameDetails game_details = *((struct GameDetails *)gameDetails);
pthread_t *threads = (pthread_t *)malloc(game_details.PlayersCount * sizeof(pthread_t));
game_manager.Players = (struct Player *)malloc(game_details.PlayersCount * sizeof(struct Player));
game_manager.WinnersTable = (int *)malloc(game_details.PlayersCount * sizeof(int));
game_manager.Rounds = game_details.RoundsCount;
IsGameActive = 1;
for(int i = 0; i < game_details.PlayersCount; i++){
game_manager.Players[i].isFinished = 0;
game_manager.Players[i].id = i;
pthread_create(&threads[i], NULL, PlayerFunc, &game_manager.Players[i]);
}
for(int i = 0; i < game_manager.Rounds; i++){
pthread_mutex_lock(&lock);
while(!IsRoundEnded(game_details.PlayersCount)){
pthread_cond_wait(&cond, &lock);
}
SetWinnerToRound(i + 1, game_details.PlayersCount);
StartNewRound(game_details.PlayersCount);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
IsGameActive = 0;
printf("\nGame end ! The winner of the game is ...\n");
printWinnerToGame(game_details.PlayersCount);
}
void* PlayerFunc(void* playerDetails){
struct Player player = *((struct Player *)playerDetails);
while(IsGameActive){
pthread_mutex_lock(&lock);
while(player.isFinished){
pthread_cond_wait(&cond, &lock);
}
player.number = (rand() % (100 - 1 + 1)) + 1;
printf("%d", player.number);
player.isFinished = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
}
void SetWinnerToRound(int roundNumber, int playersCount){
int max = game_manager.Players[0].number;
int id = 0;
for(int i = 1; i < playersCount; i++){
if(game_manager.Players[i].number > max){
max = game_manager.Players[i].number;
id = i;
}
}
printf("--Round %d: winner is player number %d--\n", roundNumber, id + 1);
game_manager.WinnersTable[id]++;
}
void StartNewRound(int playersCount){
for(int i = 1; i < playersCount; i++){
game_manager.Players[i].isFinished = 0;
}
}
void printWinnerToGame(int playersCount){
int max = game_manager.Players[0].number;
int id = 0;
for(int i = 1; i < playersCount; i++){
if(game_manager.Players[i].number > max){
max = game_manager.Players[i].number;
id = i;
}
}
printf("Player number %d is the winner of the game !!\n", id + 1);
}
int IsRoundEnded(int playersCount){
for(int i = 0; i < playersCount; i++)
if(!game_manager.Players[i].isFinished)
return 0;
return 1;
}
But the problem is that when i run it the output is
the image is in the link
and the terminal is stuck like it show in the image.
I think that maybe the threads is in deadlock mode, isnt it?
Thank you for your help!
UPDATE
So I heard to #n.m. and to #pilcrow, and in PlayerFunc i changed the Player object to pointer to the argument cause before the change the function made a copy of the argument and every time i tried to change something in the object it didnt change in the PlayerThread. In addition i changed the pthread_cond_signal to pthread_cond_broadcast and now it work. Thank you all!
void* PlayerFunc(void* playerDetails){
struct Player player = *((struct Player *)playerDetails);
....
PlayerFunc creates a copy of its argument representing that thread/player's state. ManagerGameFunc will never see modifications to that copy, in particular whether it isFinished or not.
All your threads follow the same pattern:
pthread_mutex_lock(&lock);
while(!predicate(....)){
pthread_cond_wait(&cond, &lock);
}
....
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
First time through the loop all predicates are false. All threads therefore peacefully sleep in pthread_cond_wait. It is never signalled, because neither thread has a chance to progress and signal it. So they wait forever.

malloc() is returning the same address multiple times, even when I haven't used free()

EDIT: I did use free(), ignore the title.
The gist is that every time malloc() is called, the address 0x8403620
is returned, which I found out using Gdb.
tellers[i] = create_teller(0, i, NULL);
I first use malloc() on line 72 to create 3 teller structures. The first addressed returned, visible through Gdb, is 0x84003620. The second is
0x84033a0, the third 0x84034e0. Everything seems fine.
clients[i] = create_client(0, i, -1, -1);
Then I use malloc() on line 77 with the create_client() function to
create 100 clients. The first address, assigned to client[0], is ...
0x8403620. The same as tellers[0]. It gets worse. The next address
returned from malloc() is 0x8403620 again for when i = 1, and so
on for i = 3, 4, ..., 99.
It isn't inherently the create_client() or the create_teller() functions, but
instead the malloc() function itself.
This is simply a very odd situation.
Now, I'd like to ask: Am I using malloc() wrong? Or is my version of malloc() bugged and should I somehow reinstall whatever it is? It's most likely my code since it works for creating the tellers, just not for the clients.
Here is the full code:
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <assert.h>
typedef struct teller teller_t;
typedef struct client client_t;
teller_t * create_teller (pthread_t thread_id, int id, client_t *assigned_client);
client_t * create_client (pthread_t thread_id, int id, int operation, int amount);
void * run_teller (void *arg);
void * run_client (void *arg);
/* types of operations */
#define DEPOSIT 0
#define WITHDRAW 1
#define NUM_TELLERS 3
#define NUM_CLIENTS 100
struct client {
pthread_t thread_id;
int id;
int operation;
int amount;
};
struct teller {
pthread_t thread_id;
int id;
bool available;
client_t *assigned_client;
};
client_t *clients[100];
teller_t *tellers[3];
/* only 2 tellers at a time can access */
sem_t safe;
/* only 1 teller at a time can access */
sem_t manager;
/* amount of tellers available, at most 3 */
sem_t line; /* rename to available? */
/* each teller waiting for a client to be assigned to them */
sem_t wait_for_client[3];
int
main (int argc, char **argv) {
(void) argc;
(void) argv;
srand(time(NULL));
/* This also tells us how many clients have been served */
int client_index = 0;
sem_init(&safe, 0, 2);
sem_init(&manager, 0, 1);
sem_init(&line, 0, 0);
for (int i = 0; i < 3; i++)
sem_init(&wait_for_client[i], 0, 0);
for (int i = 0; i < NUM_TELLERS; i++) {
tellers[i] = create_teller(0, i, NULL);
pthread_create(&tellers[i]->thread_id, NULL, run_teller, (void *) tellers[i]);
}
for (int i = 0; i < NUM_CLIENTS; i++) {
clients[i] = create_client(0, i, -1, -1);
pthread_create(&clients[i]->thread_id, NULL, run_client, (void *) clients[i]);
}
/* DEBUG
for (int i = 0; i < NUM_CLIENTS; i++) {
printf("client %d has id %d\n", i, clients[i]->id);
}
*/
// No threads should get past this point!!!
// ==------------------------------------==
// Should all of this below be handled by the clients instead of main?
while (1) {
if (client_index >= NUM_CLIENTS) {
// TODO:
// tell tellers that there are no more clients
// so they should close, then then close the bank.
break;
}
sem_wait(&line);
for (int i = 0; i < 3; i++) {
if (tellers[i]->available) {
int client_id = clients[client_index]->id;
//printf("client_index = %d\n", client_index); // DEBUG
tellers[i]->assigned_client = clients[client_index++];
tellers[i]->available = false;
printf(
"Client %d goes to Teller %d\n",
client_id,
tellers[i]->id
);
sem_post(&wait_for_client[i]);
break;
}
}
//sem_post(&line); // Is this needed?
}
return EXIT_SUCCESS;
}
teller_t *
create_teller (pthread_t thread_id, int id, client_t *assigned_client) {
teller_t *t = (teller_t *) malloc(sizeof(teller_t));
if (t == NULL) {
printf("ERROR: Unable to allocate teller_t.\n");
exit(EXIT_FAILURE);
}
t->thread_id = thread_id;
t->id = id;
t->available = true;
t->assigned_client = assigned_client;
return t;
}
/* TODO: Malloc returns the same address everytime, fix this */
client_t *
create_client (pthread_t thread_id, int id, int operation, int amount) {
client_t *c = malloc(sizeof(client_t));
if (c == NULL) {
printf("ERROR: Unable to allocate client_t.\n");
exit(EXIT_FAILURE);
}
c->thread_id = thread_id;
c->id = id;
c->operation = operation;
c->amount = amount;
return c;
}
void *
run_teller (void *arg) {
teller_t *t = (teller_t *) arg;
printf("Teller %d is available\n", t->id);
while (1) {
/* tell the line that a teller is available */
sem_post(&line);
/* pass when the line assignes a client to this teller */
sem_wait(&wait_for_client[t->id]);
assert(t->assigned_client != NULL);
if (t->assigned_client->operation == WITHDRAW) {
}
else {
}
}
free(arg);
pthread_cancel(t->thread_id);
return NULL;
}
void *
run_client (void *arg) {
client_t *c = (client_t *) arg;
c->operation = rand() & 1;
printf(
"Client %d waits in line to make a %s\n",
c->id,
((c->operation == DEPOSIT) ? "Deposit" : "Withdraw")
);
free(arg);
pthread_cancel(c->thread_id);
return NULL;
}
Then I use malloc() on line 77 with the create_client() function to create 100 clients.
Not exactly, you create one object, then you spawn a thread that manages that object, run_client() and then repeat. But run_client() basically does nothing except free() your client object! So malloc is totally right returning the same address again, as it is now free memory.
It just happens that your client threads are faster than your main one. Your problem here is that you are freeing the objects from secondary threads while leaving the dangling pointers in the global pointer array. If you use that array for debugging purposes, then nothing is actually wrong here, but if you want to use the client objects somewhen in the future, then you should not free your clients in the first place.

Producer–Consumer & Condition Variables program gets stuck in a infinite loop

When I run my program( running in C ) with usleep it gets stuck in an infinite loop. Without usleep the program doesnt run concurrently though. Any help will be much appreciated.
The program is supposed to allow producers make food while consumers take the food at the same time. My program gets stuck after adding about 5 items and stops. I think it could be a thread not being unlocked but I cant figure it out.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
// rc stands for return code
#define NUM_THREADS 4 // declare consumers
#define NUM_PRODUCERS 2 // declare producers
#define MAX_BUFFER 10 // declare max buffer
pthread_mutex_t bufferBox; // delcare buffer
struct foodItem{ // structure for food
int serialCode;
int producer;
struct foodItem * next;
};
struct buffer{ // Structure for buffer
int size;
struct foodItem * head;
};
struct buffer * myBuffer;
void addFood(int producer, struct buffer * buffer);
void removeItem(struct buffer * buffer);
int serial;
void addFood(int producer, struct buffer * buffer){ // ADD TO BUFFER FUNCTION
struct foodItem * newItem = malloc(sizeof(struct foodItem));
newItem -> producer = producer;
newItem -> serialCode = serial;
if(buffer->size==0){
buffer-> head = newItem;
buffer->size++;
printf("item added serial%d\n",serial);
serial++;
}
else{
struct foodItem * item = buffer ->head;
while(item->next != NULL ){
item = item-> next;
}
item ->next =newItem;
buffer->size++;
printf("item added serial%d\n",serial);
serial++;
}
}
void removeItem(struct buffer * buffer){ //REMOVE FROM BUFFER FUNCTION
if(buffer->size ==1){
free(buffer->head);
}
else{
struct foodItem * temp = buffer -> head;
buffer -> head = buffer ->head->next;
free(temp);
}
buffer->size--;
printf("item removed\n");
}
void *Producers(void *threadid){
int i =11;
while(i>0){
if(myBuffer->size < MAX_BUFFER){
pthread_mutex_lock(&bufferBox);
addFood((int)threadid, myBuffer);
addFood((int)threadid, myBuffer);
pthread_mutex_unlock(&bufferBox);
usleep(20000);
}
else{
printf("OverFlow\n");
}
i--;
}
pthread_exit(NULL);
}
void *Consumers(void *threadid) {
usleep(20000);
int i =6;
while( i >0){
if(myBuffer->size > 0){
pthread_mutex_lock(&bufferBox);
removeItem(myBuffer);
pthread_mutex_unlock(&bufferBox);
usleep(15000);
}
else{
printf("UnderFlow\n");
}
i--;
}
pthread_exit(NULL);
}
int main (int argc, const char * argv[]) {
pthread_t consumers[NUM_THREADS];
pthread_t producers[NUM_PRODUCERS];
long rc,t,i;
int size =0;
myBuffer = malloc(sizeof(struct buffer));
for (t=0;t<NUM_PRODUCERS;t++) {
printf("Creating Producers %ld\n",t);
rc = pthread_create(&producers[t],NULL,Producers,(void *)t); // initial producer
if (rc) {
printf("ERROR return code from pthread_create(): %ld\n",rc);
exit(-1);
}
}
//usleep(10000);
for (t=0;t<NUM_THREADS;t++) {
printf("Creating Consumers %ld\n",t);
rc = pthread_create(&consumers[t],NULL,Consumers,(void *)t); // initial consumers
if (rc) {
printf("ERROR return code from pthread_create(): %ld\n",rc);
exit(-1);
}
}
// wait for threads to exit
for(t=0;t<NUM_THREADS;t++) {
pthread_join(producers[t], NULL);
}
// wait for threads to exit
for(t=0;t<NUM_THREADS;t++) {
pthread_join(consumers[t], NULL);
}
return 0;
}
You need to be careful to initialize any data before using it, for example your addFood(...) routine at the top add a line like this
newItem -> next = NULL;
Similarly in your removeItem(...) function;
if(buffer->size ==1){
free(buffer->head);
buffer->head = NULL;
}
Also as #EOF says in his comment above use the mutex to protect access to buffer->size in your Producers(...) and Consumers(...) routines. For example;
pthread_mutex_lock(&bufferBox);
if(myBuffer->size < MAX_BUFFER) {
....
pthread_mutex_unlock(&bufferBox);
After fixing all of these problems your producers seem to exit last leaving the queue completely full. Not sure what behavior you expect.

program spinning on pthread lock

After banging my head against a wall for a few hours during this exercise, I am stuck at that wall.
First off, this is a program designed to find and print all prime numbers between 1 and ceiling, where ceiling is some user input. The design is to implement POSIX threads.
In my program, it runs successfully until on one of the later iterations in the thread's method. When it gets to that later iteration, it steps to the line pthread_mutex_lock(lock); and spins, forcing me to kill it with Ctrl+z. The 2 input's I've been using are 1 for the number of threads and 10 for the ceiling. This flaw is reproducible as it happens every time I've tried it. note: although this code should be able to implement multiple threads, I'd like to get it working correctly with 1 child thread before adding more.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int* numbermarker = NULL;
int* buffer = NULL;
int* checked = NULL;
int pullposition = 0;
int placeposition = 0;
pthread_mutex_t* lock;
int ceiling;
/*This method places one of the primes in the buffer. It
offers a safe way to manage where the next value will be placed*/
void placevalue(int value){
buffer[placeposition] = value;
placeposition++;
}
void* threadmethod(){
int i;
int k;
int l;
while(1){
printf("pull %d number %d \n",pullposition, buffer[pullposition]);
pthread_mutex_lock(lock);
printf("FLAG\n");
l = buffer[pullposition];
pullposition++;
printf("pullTWO %d number %d \n",pullposition, buffer[pullposition-1]);
pthread_mutex_unlock(lock);
for(k=l+1;k<=ceiling;k++){
if(k%l){
if(k%2){
checked[k]=1;
placevalue(k);
}
}
else{
numbermarker[k-1] = 1;
}
}
int sum=0;
for(i=0; i<ceiling; i++){
if(numbermarker[i]){
checked[i] = numbermarker[i];
}
printf("checked|%d|%d|%d|%d|%d|%d|%d|%d|%d|%d|\n",
checked[0], checked[1], checked[2], checked[3], checked[4], checked[5], checked[6], checked[7], checked[8], checked[9]);
sum += checked[i];
printf("sum %d ceiling %d\n",sum,ceiling);
}
printf("number |%d|%d|%d|%d|%d|%d|%d|%d|%d|%d|\n",
numbermarker[0], numbermarker[1], numbermarker[2], numbermarker[3], numbermarker[4], numbermarker[5], numbermarker[6], numbermarker[7], numbermarker[8], numbermarker[9]);
if(sum == ceiling){
return NULL;
}
}
}
int main()
{
int numthreads;
int i;
printf("Enter number of threads: \n");
scanf("%d", &numthreads);
printf("Enter the highest value to check \n");
scanf("%d", &ceiling);
/* This will hold 1's and 0's.
1 = number has been checked or is
confirmed not to be a prime
0 = number is a possible prime
The idea behind these values is that the next
prime can always be identified by the 0 with
the lowest index
*/
numbermarker = (int*)malloc(sizeof(int)*(ceiling));
checked = (int*)malloc(sizeof(int)*(ceiling));
/*This will hold the primes as they are found*/
buffer = (int*)malloc(sizeof(int)*(ceiling));
/*allocate space for the lock*/
lock = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
pthread_mutex_init(lock,NULL);
for(i=0; i<ceiling; i++){
if(i<1){
numbermarker[i] = 1;
}
else{
numbermarker[i] = 0;
}
checked[i]=0;
buffer[i]=0;
printf("%d \n",numbermarker[i]);
}
checked[0]=1;
placevalue(2);
printf("checked|%d|%d|%d|%d|%d|%d|%d|%d|%d|%d|\n", checked[0], checked[1], checked[2], checked[3], checked[4], checked[5], checked[6], checked[7], checked[8], checked[9]);
pthread_t **tid = (pthread_t **) malloc(sizeof(pthread_t *) * numthreads);
for(i=0;i<numthreads;i++){
tid[i] = (pthread_t *) malloc(sizeof(pthread_t));
}
for(i=0;i<numthreads;i++){
if(pthread_create(tid[i],
NULL,
threadmethod,
NULL)){
printf("Could not create thread \n");
exit(-1);
}
}
for(i=0;i<numthreads;i++){
if(pthread_join(*tid[i], NULL)){
printf("Error Joining with thread \n");
exit(-1);
}
free(tid[i]);
}
free(tid);
for(i=0;i<ceiling;i++){
if(numbermarker[i] == 0){
printf("%d sdfsddd \n", numbermarker[i]);
printf("%d \n", i+1);
}
}
free(buffer);
free(numbermarker);
buffer=NULL;
numbermarker=NULL;
return(0);
}
I've tried your code and in
void placevalue(int value)
{
buffer[placeposition] = value;
placeposition++;
}
placeposition goes beyond the size of buffer. This results in undefined behaviour, a very plausible outcome of which is the trashing of the mutex (which is malloc()ed right after buffer).
On top of that, there's a race condition is placevalue(). However, if you're using a single worker thread, you are not (yet) running into it.

one consumer multiple producer in c prevent racing when resuming after full buffer

I made a circular buffer with multiple clients writing a message of different length into a buffer. The server reads them out. It based the code an the consumer/producer problem.
The problem is when the buffer is full and the server removes all the data from the buffer the client is signaled to resume it's writing operations but instead another client (in another thread) start writing it message in the buffer. I want client that was already writing before the buffer was full to resume it's operations so that the message doesn't arrive out of order.
This is my code (i removed a lot of test code)
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#define BUFFER_SIZE 8
#define NUM_THREADS 4
struct cBuf{
char *buf;
int size;
int start;
int end;
pthread_mutex_t mutex;
pthread_cond_t buffer_full;
pthread_cond_t buffer_empty;
};
struct cBuf cb;
void buf_Init(struct cBuf *cb, int size) {
int i;
cb->size = size + 1;
cb->start = 0;
cb->end = 0;
cb->buf = (char *)calloc(cb->size, sizeof(char));
for (i=0;i<size;i++) cb->buf[i]='_';
}
void buf_Free(struct cBuf *cb) {
free(cb->buf);
}
int buf_IsFull(struct cBuf *cb) {
return (cb->end + 1) % cb->size == cb->start;
}
int buf_IsEmpty(struct cBuf *cb) {
return cb->end == cb->start;
}
int buf_Insert(struct cBuf *cb, char *elem) {
int i,j;
pthread_mutex_lock(&(cb->mutex));
for (i=0; i < strlen(elem); ++ i){
if (buf_IsFull(cb)==1) printf("\nProducer (buf_Insert) is waiting because of full buffer");
while(buf_IsFull(cb)){
pthread_cond_signal(&(cb->buffer_full));
pthread_cond_wait(&(cb->buffer_empty),&(cb->mutex));
}
cb->buf[cb->end] = elem[i];
cb->end = (cb->end + 1) % cb->size;
printf("%c [INPUT]",elem[i]);
}
pthread_cond_signal(&(cb->buffer_full));
pthread_mutex_unlock(&(cb->mutex));
return 0;
}
int buf_Read(struct cBuf *cb, char *out) {
int i,j;
pthread_mutex_lock(&(cb->mutex));
if (buf_IsEmpty(cb))printf("\nConsumer (buf_Read) is waiting because of empty buffer\n");
while(buf_IsEmpty(cb)){
pthread_cond_wait(&(cb->buffer_full),&(cb->mutex));
}
for (i=0;i<BUFFER_SIZE-1;i++){
printf("\n");
if (cb->start == cb->end) break;
out[i] = cb->buf[cb->start];
cb->buf[cb->start] = '_';
cb->start = (cb->start + 1) % cb->size;
printf("%c [OUTPUT]",out[i]);
}
pthread_cond_signal(&(cb->buffer_empty));
pthread_mutex_unlock(&(cb->mutex));
return 0;
}
void * client(void *cb){
pthread_detach(pthread_self());
struct cBuf *myData;
myData = (struct cBuf*) cb;
char input[]="Hello World!";
if (buf_Insert(myData, input)){
//succes on return 0
printf("\n");
}
return 0;
}
int main(void) {
char out[60];
pthread_t thread;
int i;
/* Initialise conditioners*/
pthread_cond_init(&(cb.buffer_full),NULL);
pthread_cond_init(&(cb.buffer_empty),NULL);
buf_Init(&cb, BUFFER_SIZE);
for (i = 0; i<NUM_THREADS; i++){
if(pthread_create (&thread,NULL, client, (void *) &cb) !=0){
} else {
}
}
while (1){
if (buf_Read(&cb,out)){
}
}
//empty the buffer; free the allocated memory
buf_Free(&cb);
return 0;
}
I already explained in comment in Producer/consumer seems to be in deadlock when buffer is smaller than input from producer, but those are comments, so here goes as answer:
You should never ever have partial message in the queue. Make sure you never write one.
You can check whether there is enough space before starting to write the message and wait for buffer_empty straight away if there's not, or you can change the queue to send shared pointers to allocated data (either pass ownership to consumer or reference-counted) or something, so each message only takes up one slot in the queue and allocated memory for the rest. What's best will depend on the exact nature of your message. Anything will do as long as there are no partial messages.
While it would be possible to record which particular writer needs to finish a message and wake just that, it would be awfully complicated. Synchronization is hard as it is, don't make it any harder by placing additional requirements on it.
In fact unless this is a homework (in a sense you do it to learn how synchronization works), just look for ready-made message queues. The SysV-IPC ones or unix-domain sockets in datagram mode are two options that come to mind, or look for some library that does.

Resources