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);
}
Related
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.
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.
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.
I'm not sure whats wrong with the program below, but it doesn't print each and every language once, but randomly some more often, some more less and some wont print
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
char *messages[] = {
"English: Hello World!",
"French: Bonjour, le monde!",
"Spanish: Hola al mundo",
"Klingon: Nuq neH!",
"German: Guten Tag, Welt!",
"Russian: Zdravstvytye, mir!",
"Japan: Sekai e konnichiwa!",
"Latin: Orbis, te saluto!"
};
#define NUM_MESSAGES (sizeof( messages ) / sizeof( char* ))
void *PrintHello( void *messageid )
{
pthread_t taskid;
int *id_ptr, message_num;
taskid = pthread_self();
printf( "This is thread with ID %lu.\n", taskid );
message_num = *((int *) messageid);
printf( "%s \n", messages[message_num] );
pthread_exit( NULL );
}
int main( int argc, char *argv[] )
{
pthread_t threads[NUM_MESSAGES];
int rc, i;
for( i = 0; i < NUM_MESSAGES; i++ ) {
void * argument = (void*) &i;
rc = pthread_create( &threads[i], NULL, PrintHello, argument );
if( rc ) {
printf( "ERROR; return code from pthread_create() is %d\n", rc );
exit( -1 );
}
}
for( i = 0; i < NUM_MESSAGES; i++ ) {
pthread_join( threads[i], NULL );
}
pthread_exit( NULL );
}
I guess the problem is somehow connected with the argument pointer. I tried to lock different parts but with no success.
You're passing the address of the variable i, which the main thread keeps changing. So you're at the mercy of scheduling: will anyone change i before your thread has a chance to run ?
Instead, you could try directly passing the string, greatly simplifying the code:
rc = pthread_create( &threads[i], NULL, PrintHello, messages[i]);
void *PrintHello(void *arg)
{
char *msg = arg;
printf("%s\n", msg);
return NULL;
}
There's another, poorer alternative where you pass the actual value of i as the argument (not its address).
This is a typical race condition.
To be exact, after a new thread is created, the executing order of the threads determines the program outcome. There are two situations:
When the thread function PrintHello is executed before the next increments i++ and the assignment void * argument = (void*) &i; in main thread, it outputs what you expect.
When the new thread PrintHello has been created but does not get scheduled until the next i++ executed in main thread. In this situation, your reference of argument in the thread function, namely message_num = *((int *) messageid); is not what you expect.
A solution for this is to dynamically allocate (using malloc)argument, and free them in the thread function after using it.
One way to pass scalar integer arguments to thread functions is to (ab-)use the following text from ยง6.3.2.3 of the C99 standard:
(5) An integer may be converted to any pointer type. Except as previously specified, the
result is implementation-defined, might not be correctly aligned, might not point to an
entity of the referenced type, and might be a trap representation.
Except for the last part of the second sentence, the following code should work on most systems:
int int_val;
...
pthread_create(..., ..., thread_func, (void *)int_val);
and then in thread_func cast it back to integer:
void *thread_func (void *data)
{
int int_arg = (int)data;
...
}