This is my main function, where NO_RECIEVERS = 3. I am trying to differentiate between the writer and reader threads using the value of i that i send.
int main() {
int status, i;
pthread_t tr[NO_RECIEVERS], tw[NO_SENDERS], bd;
i=1;
for(i=1; i<=NO_SENDERS; i++) {
pthread_create(&tw[i-1], NULL, writer, &i);
}
for(i=1; i<=NO_RECIEVERS; i++) {
printf("%d\n", i);
pthread_create(&tr[i-1], NULL, reader, &i);
}
pthread_create(&bd, NULL ,daemon_thread, NULL);
for(i=1; i<=NO_SENDERS; i++) {
pthread_join(tw[i-1], NULL);
}
for(i=1; i<=NO_RECIEVERS; i++) {
pthread_join(tr[i-1], NULL);
}
pthread_join(bd, NULL);
return 0;
}
My reader function is as follows
void* reader(void *val) {
int ret, fd, id;
struct mssg data;
id = *(int*)val;
printf("id: %d %d\n", id, *(int*)val);
while(1) {
But this function seems to be creating threads with id some random values.. i get a log like this
...
id: 1 1
...
id: 2 2
...
id: 1 1
Next time i get.. its kind of random
...
id: 1 1
...
2
id: 2 2
...
id: 4 4
But the values i am assigning are limited to 1,2,3
You passed &i to all the threads you created... so each one has a pointer to i, and when they dereference that to read the value of i, and what they read is whatever i happens to be at the time.
If you want to pass the value of i at the time of the pthread_create, I suggest malloc() a small piece of memory, copy i to it and pass the malloced thing to the thread (which can read it and the free() the memory. Or any other method that provides a copy of i in a different location for each thread created.
Related
I have this program:
void *func(void *arg) {
pthread_mutex_lock(&mutex);
int *id = (int *)arg;
printf("My ID is %d\n" , *id);
pthread_mutex_unlock(&mutex);
}
int main() {
int i;
pthread_t tid[3];
// Let us create three threads
for (i = 0; i < 3; i++) {
pthread_create(&tid[i], NULL, func, (void *)&i);
}
for (i = 0; i < 3; i++) {
pthread_join(tid[i], NULL);
}
pthread_exit(NULL);
return 0;
}
I expected it to output this:
My ID is 0
My ID is 1
My ID is 2
But instead I get random output, such as this:
My ID is 0
My ID is 0
My ID is 2
Since I already added mutex lock, I thought it would solve the problem. What else did I do wrong? Is this related to race condition?
Here id points to the same variable i in main for all the threads.
int *id = (int *)arg;
printf("My ID is %d\n" , *id);
But the variable i is constantly being update by the two for-loops in main behind the threads back. So before the thread reaches the point of printf, the value of i, and therefore also the value of *id, may have changed.
There are a few ways to solve this. The best way depends on the use case:
Wait in main until the thread signals that it has made a copy of *id before modifying i or letting it go out of scope.
Declare and initialize an array, int thread_id[], and create the threads like this:
pthread_create(&tid[i], NULL, func, &thread_id[i]);
malloc some memory and and initialize it with a copy of i:
int *thread_id = malloc(sizeof(*thread_id));
*thread_id = i
pthread_create(&tid[i], NULL, func, thread_id);
Just don't forget to free your memory int the thread when you are finished using it. Or in main if the thread fails to start.
If i fits in a void * can pass its content directly as a parameter to the thread. To make sure it fits, you can declare it as intptr_t rather than int
(We basicly abuse the fact that pointers are nothing more than magic integers) :
void *func(void *arg) {
pthread_mutex_lock(&mutex);
// Here we interpret a pointer value as an integer value
intptr_t id = (intptr_t )arg;
printf("My ID is %d\n" , (int)id);
pthread_mutex_unlock(&mutex);
}
int main() {
intptr_t i;
pthread_t tid[3];
// Let us create three threads
for (i = 0; i < 3; i++) {
// Here we squeeze the integer value of `i` into something that is
// supposed to hold a pointer
pthread_create(&tid[i], NULL, func, (void *)i);
}
for (i = 0; i < 3; i++) {
pthread_join(tid[i], NULL);
}
// This does not belong here !!
// pthread_exit(NULL);
return 0;
}
Nope, no race conditions involved. (my b) There can be a race condition on i because all threads access it. Each thread gets started with a pointer to i. However, the main problem is that there is no guarantee that the thread will start and run the critical section while i holds the value you expect, in an order that you expect.
I'm assuming you declared the variable mutex globally and called pthread_mutex_init() somewhere to initialize it.
Mutexes are great to allow only one thread to access a critical section of code at a time. So the code as you've written creates all three threads to run in parallel, but only lets one thread at a time run the following code.
int *id = (int *)arg;
printf("My ID is %d\n" , *id);
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
// Let us create a global variable to change it in threads
int g = 0;
// The function to be executed by all threads
void *myThreadFun(void *vargp)
{
// Store the value argument passed to this thread
int *myid = (int *)vargp;
// Let us create a static variable to observe its changes
static int s = 0;
// Change static and global variables
++s; ++g;
// Print the argument, static and global variables
printf("Thread ID: %d, Static: %d, Global: %d\n", *myid, ++s, ++g);
}
int main()
{
int i;
pthread_t tid;
// Let us create three threads
for (i = 0; i < 3; i++)
pthread_create(&tid, NULL, myThreadFun, (void *)&i);
pthread_exit(NULL);
return 0;
}
I was just playing with aforementioned example in multithreading in C, and I got the same thread id for 2 threads and it shouldn't be because myid is a local pointer and should print different with each one.
I got the output as following:
Thread ID: 3, Static: 2, Global: 2
Thread ID: 3, Static: 4, Global: 4
Thread ID: 3, Static: 6, Global: 6
Can someone please explain me in brief?
You pass the very same pointer to all three threads. All threads will dereference the same pointer, getting the same value.
And because you call pthread_exit, the data the pointer is pointing to will not be alive anymore. And that means the dereference will lead to undefined behavior.
Furthermore since you access and modify shared data without synchronization you have data-races leading yet again to undefined behavior.
The first two problems can be easily solved by passing the value of i instead of a pointer to it. This is one of the very few cases where most people think it's okay to pretend that an integer is a pointer. You have to do some casting to make it work though:
pthread_create(&tid, NULL, myThreadFun, (void *) (intptr_t) i);
Then you have to do the opposite casting when getting the value:
int myid = (int) (intptr_t) vargp;
I got the same thread id for 2 threads and it shouldn't be because myid is a local pointer and should print different with each one.
myid is a local pointer, but it's actually pointing at an address from another thread. myid in all 3 threads you created pointed to the same address of i in main. So when you dereference myid, all threads read from the same location.
There are few issues.
Since main calls, pthread_exit, once the main thread exits and you can no longer access i from other threads. This is undefined behaviour.
All the threads actually read i (through myid). This is a data race - more than one thread accessing i without any
synchronisation.
Note that scope of an object doesn't determine the lifetime of an object. They are related but not the same.
the following proposed code:
cleanly compiles
performs the desired functionality
corrects the problems found in the OPs posted code
checks for (most) error conditions
uses a proper signature for the main() function
And now the proposed code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#define NUM_THREADS 3
// Let us create a global variable to change it in threads
int g = 0;
pthread_mutex_t myMutex;
// The function to be executed by all threads
void *myThreadFun( void *vargp )
{
// Store the value argument passed to this thread
int myid = (int) (intptr_t) vargp;
// Let us create a static variable to observe its changes
static int s = 0;
pthread_mutex_lock( &myMutex );
// Change static and global variables
++s;
++g;
// Print the argument, static and global variables
printf("Thread ID: %d, Static: %d, Global: %d\n", myid, s, g);
pthread_mutex_unlock( &myMutex );
pthread_exit( NULL );
}
int main( void )
{
pthread_t tid[ NUM_THREADS ] = {0};
if (pthread_mutex_init(&myMutex, NULL) != 0)
{
perror( "pthread_mutex_init failed" );
exit( EXIT_FAILURE );
}
// implied else, init successful
// Let us create three threads
for ( int i = 0; i < NUM_THREADS; i++)
{
if(pthread_create(&tid[i], NULL, myThreadFun, (void *) (intptr_t) i) != 0 )
{
perror( "pthread_create failed" );
exit( EXIT_FAILURE );
}
}
// collect the threads
for( int i=0; i< NUM_THREADS; i++ )
{
if( pthread_join( tid[i], NULL ) != 0 )
{
perror( "pthread_join failed" );
}
}
pthread_mutex_destroy( &myMutex );
return 0;
}
A typical run of the program results in the following output:
Thread ID: 0, Static: 1, Global: 1
Thread ID: 2, Static: 2, Global: 2
Thread ID: 1, Static: 3, Global: 3
Note: the field claiming to be the thread ID is only the order that the threads were created, not the actual thread id.
When I run the following code it seems like the printout is not right.
void thread_Calc(int *pos) {
printf("recieved %d\n", *pos);
sig = -1;
mandel_Calc(&slices[*pos],maxIterations,&res[(*pos)*slices[*pos].imSteps*slices[*pos].reSteps]);
counter++;
array[counter] = *pos;
sig = *pos;
}
int main(int argc, char *argv[]) {
while (WinH % nofslices != 0) { nofslices++;}
slice_height = WinH/nofslices;
level = 1;
while (1) {
for (i=0; i<nofslices; i++){
array[i] = -1;
}
y=0;
sig = -1;
counter = -1;
for(i=0; i<nofslices; i++){
printf("Passing %d\n", i);
check=pthread_create(&worker[i], NULL, (void*)thread_Calc, (void*)(int *)&i);
if (check!=0) {
printf("Error in pthread_create\n");
return 0;
}
while (sig==-1||array[counter]==-1){
}
}
}
}
(This is just a part of my code, so assume that every variable is right and has a value).
The result I get is something like:
Passing 1
Passing 2
recieved 2
recieved 2
Passing 3
Passing 4
recieved 4
recieved 4
Passing 5
Passing 6
Passing 7
Passing 8
Passing 9
which seems like I can't always pass the right argument in pthread_create or something.
#Andrew is right. You pass a pointer not a value, so as soon as you change "i" in the main thread the value is changed in the parameter received by the created thread. You need to create a copy and pass it to the thread.
See pthread_create : passing an integer as the last argument
In this code:
for(i=0; i<nofslices; i++){
printf("Passing %d\n", i);
check=pthread_create(&worker[i], NULL, (void*)thread_Calc, (void*)(int *)&i);
the value of i continues to change after each thread gets started.
You pass the address of i, so when it gets dereferenced in the child thread, it holds whatever value your main thread has put into it at that time.
I've a problem when I try to sychronize my threads. I have the next code:
static void* CarProcess(void *str);
int main()
{
thread_t *pthreadsArray;
pthreadsArray = (thread_t*)malloc(sizeof(thread_t) * 10);
for (int i = 0; i < 10; i++)
{
int pthread = mythread_create(&pthreadsArray[i], NULL, CarProcess, i);
}
for (int i = 0; i < 10; i++)
{
mythread_join(pthreadsArray[i], NULL);
}
}
static void* CarProcess(void *str)
{
while(1){
printf("Thread ID: %i\n", str);
}
}
When I execute the program, I have this output:
Thread ID: 0
Thread ID: 0
Thread ID: 0
Thread ID: 0
...
But never appears "Thread ID: 1", "Thread ID: 2", "Thread ID: 3"....or "Thread ID: 9". I think that it could be solved using Mutex, locking and unloking Mutex.. Does any body have idea how to solve that? Thanks
One possible source of the problem is that str is not really an int variable. You need to do some casting (both when creating the thread and when getting the argument).
To create a the thread and to properly pass the integer to ity ou first need to cast the value to an intptr_t, which is a standard integer type big enough to fit both an integer or a pointer. Then you should cast it to a generic pointer (i.e. void *):
pthread_create(&pthreadsArray[i], NULL, CarProcess, (void *) (intptr_t) i);
Then to get the integer value inside the thread function you need to do the opposite casting:
static void* CarProcess(void *str)
{
int i = (int) (intptr_t) str;
printf("Thread ID: %i\n", i);
}
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);
}