Struct changes after being passed to a pthread - c

I'm trying to make a function that has to create a series of pthreads. I'm trying to keep track of each thread by assigning it a unique int t. However, when I try to make more than one thread, the value of t changes, every time I increment it in the main function. It should be pass by value so why is it changing?
// Struct //
typedef struct threadArg {
int verbose;
int listSize;
int thread;
int (*list)[];
} threadArg;
// In main //
for(t=0; t < numThreads; t++){
printf("Creating thread %ld...\n", t);
struct threadArg arg = {
.verbose = verbose,
.list = &arr,
.listSize = size,
.thread = t
};
printf("t: %d\n", (arg.thread));
status = pthread_create(&threadID[t], NULL, threadSort, (void*)&arg);
if (status){
printf("ERROR: failed to create thread", t);
exit(-1);
}
}
// Thread Sort function //
void *threadSort(void* arguments) {
// *** Bubble Sort ***
threadArg* arg = (threadArg*) arguments;
int verbose = arg->verbose;
int size = arg->listSize;
int (*arr)[size] = arg->list;
int t = arg->thread;
if (verbose & INIT) { printf("Thread %d initalized!\n", t); }
}
Thank you for your help,
Wally

It should be pass by value
No, this line passes it "by reference", that is passes the address of arg:
status = pthread_create(&threadID[t], NULL, threadSort, (void*)&arg)
The instance of arg in your code is used and destroyed and recreated for each iteration of the loop.
To fix this modfiy you code like follows:
void * threadSort(void * arguments);
[...]
struct threadArg arg = {
.verbose = verbose,
.list = &arr,
.listSize = size,
.thread = 0,
};
struct threadArg args[t] = {0};
for(t=0; t < numThreads; t++)
{
printf("Creating thread %ld...\n", t);
args[t] = arg;
args[t].thread = t;
printf("t: %d\n", arg.thread);
status = pthread_create(threadID + t, NULL, threadSort, args + t);
[...]
This introduces an array of struct arg with an element for each sperate thread, being nitialised by the value of threadArg, which is not used elsewhere but to have a common initialisation of whag is being passed to the thread function.

Related

Accessing struct pointer as pthread arg causes seg fault?

So here is a small portion of my code. Essentially I am starting another thread from a method, but when I pass the integer to the pthread, I can't access the struct members like I could only two lines before I called the thread. What has occurred since I passed this argument and run a new thread?
Note that without fail, my program always crashes immediately after printf("1\n");, I discovered this error when I realised FD_ZERO didn't work.
Struct definition (in global area):
typedef struct {
fd_set read_set, write_set;
unsigned int room_id;
char room_name[16];
} room;
Caller method:
void create_new_room(int cli_index, char buffer[]) {
pthread_mutex_lock(&mutex);
char room_name[16], password[16];
int capacity, r_index;
room *new_room = malloc(sizeof(room));
pthread_t tid;
FILE *room_file = NULL;
if((room_file = fopen("room-info.txt", "a")) == NULL) {
perror("Failed to open file.");
exit(-1);
}
// Split command data into separate strings ready to assign as room struct members
strtok(buffer, " ");
strcpy(room_name, strtok(NULL, " "));
capacity = atoi(strtok(NULL, " "));
strcpy(password, strtok(NULL, " "));
// Initialise room struct
// --Zero write set
FD_ZERO(&(new_room->write_set));
// --Set room name
strcpy(new_room->room_name, room_name);
// --Set room id
new_room->room_id = ++natural_id;
// --Add room to room_list[] and get its index in the array
for(r_index = 0; r_index < 10000; ++r_index) {
if(!room_list[r_index]) {
room_list[r_index] = new_room;
break;
}
}
// Write data to file
fprintf(room_file, "%s\n", room_name);
fprintf(room_file, "id=%u\n", natural_id);
fprintf(room_file, "owner=%s\n", client_list[cli_index]->name);
fprintf(room_file, "capacity=%d\n", capacity);
fclose(room_file);
printf("about to test\n");
printf("Testing room struct:\n");
printf("--room name = %s\n", room_list[r_index]->room_name);
printf("--room id = %u\n", room_list[r_index]->room_id);
printf("post-test.....................\n");
// Run new thread as active room
printf("Starting new room: %s\n", room_name);
pthread_create(&tid, NULL, (void *) &active_room, &r_index);
pthread_mutex_unlock(&mutex);
}
Start of new pthread method:
void active_room(void *index) {
char storage_buffer[BSIZE], output_buffer[BSIZE+32];
struct timeval timeout;
int r_index = *(int *) index;
while(1) {
// debugging lines.
printf("1\n");
printf("room name: %s\n", room_list[r_index]->room_name);
printf("room id: %u\n", room_list[r_index]->room_id);
FD_ZERO(&(room_list[r_index]->read_set));
read_set = write_set;
timeout.tv_sec = 5;
printf("2\n");
The r_index variable in create_new_room is local to the function. You then pass its address to pthread_create so the thread can use it, but then create_new_room exits, causing the lifetime of r_index to end. Then when the thread tried to dereference its argument, it is pointing to memory that is no longer valid, triggering undefined behavior.
You'll need to dynamically allocate memory for the thread's argument so it survives after create_new_room exits:
int *r_index_arg = malloc(sizeof *r_index_arg);
*r_index_arg = r_index;
pthread_create(&tid, NULL, (void *) &active_room, r_index_arg);
Then you need to make sure you free the memory in the thread:
int r_index = *(int *) index;
free(index);

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.

Passing threads a value from a for loop

I am attempting to create threads and pass each thread the value from a for loop. Here is the code segment
pthread_t *threadIDs;
int i = 0;
if(impl == 1)
{
threadIDs = (pthread_t *)malloc(sizeof(pthread_t)*reduces);
for(;i < reduces; i++)
{
pthread_create(&threadIDs[i], NULL, reduce,&i);
}
}
It is not passing the correct values of the loop, which makes sense since I am creating a race condition. What is the simplest way to pass the correct value of i from my loop?
Another question, will each thread finish executing before the next one is created and called?
You've already dynamically created an array of thread IDs. Do the same for the values you want to pass in.
pthread_t *threadIDs;
int *values;
int i = 0;
if(impl == 1)
{
threadIDs = malloc(sizeof(pthread_t)*reduces);
values = malloc(sizeof(int)*reduces);
for(;i < reduces; i++)
{
values[i] = i;
pthread_create(&threadIDs[i], NULL, reduce, &values[i]);
}
}
Each thread will be working with a different array member, so there's no race condition.
You can define a structure and assign i to the variable of the object.
#include <stdio.h>
#include <pthread.h>
typedef struct Param_ {
int index;
}Param;
static void* thread(void* p) {
Param* param = p;
printf("index: %d\n", param->index);
}
int main() {
int i = 0;
int reduces = 10;
pthread_t *threadIDs;
threadIDs = (pthread_t *)malloc(sizeof(pthread_t)*reduces);
for(; i < reduces; i++)
{
Param* p;
p = (Param*)malloc(sizeof(*p));
p->index = i;
pthread_create(&threadIDs[i], NULL, thread, p);
}
return 0;
}
What is the simplest way to pass the correct value of i from my loop?
What is to be considered "simple" depends on the use case, so here another approach to solve the issues you present:
#include <pthread.h>
pthread_mutex_t m_init;
pthread_cond_t c_init;
int init_done = 1;
void* thread_function(void * pv)
{
pthread_mutex_lock(&m_init);
size_t i = *((size_t*) pv);
init_done = 1;
pthread_cond_signal(&c_init);
pthread_mutex_unlock(&m_init);
...
}
#define THREADS_MAX (42)
int main(void)
{
pthread_t thread[THREADS_MAX];
pthread_mutex_init(&m_init, NULL);
pthread_cond_init(&c_init, NULL);
for(size_t i = 0; i < THREADS_MAX; ++i)
{
pthread_mutex_lock(&m_init);
init_done = 0;
pthread_create(&thread[i], NULL, thread_function, &i);
while (!init_done)
{
pthread_cond_wait(&c_init);
}
pthread_mutex_unlock(&m_init);
}
...
}
(error checking omitted for the sake of legibility)

Segmentation fault: core dumped during execution of multi-threaded program

I have realized that my code was too lengthy and rather hard to read.
Can you check over the way I pass in the arguments and constructing the arguments in the main body?
Essentially, provided that I have correct implementation of "produce" and "consume" functions, I want to pass in a shared circular queue and semaphores and mutexes to each produce/consume threads.
typedef struct circularQueue
{
int *items;
int *head;
int *tail;
int numProduced;
int numConsumed;
} circularQueue;
typedef struct threadArg
{
int id;
circularQueue *queue;
pthread_mutex_t *mutex;
sem_t *spaces;
sem_t *itemAvail;
int numItems;
int bufferSize;
int numProducer;
int numConsumer;
} threadArg;
pthread_t *producerThd;
pthread_t *consumerThd;
int main(int argc, char* argv[])
{
pthread_attr_t attr;
// In fo to pass to thread arg
circularQueue *myQueue;
pthread_mutex_t useSharedMem;
sem_t spaces;
sem_t itemAvail;
int numItems;
int bufferSize;
int numProducer;
int numConsumer;
int i, j, k, l;
if(argc != 5)
{
printf("Enter in 4 arguments - N B P C\n");
return -1;
}
numItems = atoi(argv[1]);
bufferSize = atoi(argv[2]);
numProducer = atoi(argv[3]);
numConsumer = atoi(argv[4]);
if(numItems == 0 || bufferSize == 0 || numProducer == 0 || numConsumer == 0)
{
printf("Parameters should not be 0\n");
return -1;
}
// Initialize list of threads
producerThd = malloc(sizeof(pthread_t) * numProducer);
consumerThd = malloc(sizeof(pthread_t) * numConsumer);
// Initialize semaphores
sem_init(&spaces, 0, bufferSize);
sem_init(&itemAvail, 0, 0);
// Initialize mutex
pthread_mutex_init(&useSharedMem, NULL);
// Initialzie thread attributes
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
// Initialize queue
myQueue = (circularQueue*)malloc(sizeof(circularQueue));
myQueue->items = (int*)malloc(sizeof(int)*bufferSize);
myQueue->head = myQueue->items;
myQueue->tail = myQueue->items;
myQueue->numProduced = 0;
myQueue->numConsumed = 0;
// thread arguments
for(i = 0; i < numProducer; i++)
{
// Initialize thraed args
threadArg *args = (threadArg*)malloc(sizeof(threadArg));
args->queue = (circularQueue*)malloc(sizeof(circularQueue));
args->mutex = &useSharedMem;
args->spaces = &spaces;
args->itemAvail = &itemAvail;
args->numItems = numItems;
args->bufferSize = bufferSize;
args->numProducer = numProducer;
args->numConsumer = numConsumer;
args->id = i;
pthread_t thisThread = *(producerThd + i);
pthread_create(&thisThread, &attr, produce, args);
}
for(j = 0; j < numConsumer; j++)
{
// Initialize thraed args
threadArg *args = (threadArg*)malloc(sizeof(threadArg));
args->queue = (circularQueue*)malloc(sizeof(circularQueue));
args->mutex = &useSharedMem;
args->spaces = &spaces;
args->itemAvail = &itemAvail;
args->numItems = numItems;
args->bufferSize = bufferSize;
args->numProducer = numProducer;
args->numConsumer = numConsumer;
args->id = j;
pthread_t thisThread = *(consumerThd + i);
pthread_create(&thisThread, &attr, consume, args);
}
for(k = 0; k < numProducer; k++)
{
pthread_join(*(producerThd+k), NULL);
}
printf("Finished waiting for producers\n");
for(l = 0; l < numConsumer; l++)
{
pthread_join(*(consumerThd+l), NULL);
}
printf("Finished waiting for consumers\n");
free(producerThd);
free(consumerThd);
free(myQueue->items);
free(myQueue);
sem_destroy(&spaces);
sem_destroy(&itemAvail);
fflush(stdout);
return 0;
}
Thank you
There are multiple sources of undefined behavior in your code, you are either compiling without enabling compilation warnings, or what I consider worst you ignore them.
You have the wrong printf() specifier in
printf("cid %d found this item %d as valid item %d\n", myArgs->id, thisItem, validItem);
because validItem is a double, so the last specifier should be %f.
Your thread functions never return a value, but you declare them to return void * which is the signature required for such functions.
You are freeing and dereferencing myQueue in the main() function but you have not initialized it because that code is commented.
Your code is also too hard to read because you have no consistent style and you mix declarations with statements, which make everything very confusing, e.g. determining the scope of a variable is very difficult.
Fixing the code will not only help others read it, but will also help you fix it and find issues quickly.

passing struct to pthread as an argument

Ok I am trying to pass pair of numbers through struct to pthread_create function in pthread. But the numbers i am passing and numbers i am getting when the function is called are different and random
Here is the struct
struct Pairs {
long i,j;
};
And inside main
void main()
{
long thread_cmp_count = (long)n*(n-1)/2;
long t,index = 0;
struct Pairs *pair;
pair = malloc(sizeof(struct Pairs));
cmp_thread = malloc(thread_cmp_count*sizeof(pthread_t));
for(thread = 0;(thread < thread_cmp_count); thread++){
for(t = thread+1; t < n; t++){
(*pair).i = thread;
(*pair).j = t;
pthread_create(&cmp_thread[index++], NULL, Compare, (void*) pair);
}
}
for(thread= 0;(thread<thread_cmp_count); thread++){
pthread_join(cmp_thread[thread], NULL);
}
free(cmp_thread);
}
And function Compare
void* Compare(void* pair){
struct Pairs *my_pair = (struct Pairs*)pair;
printf("\nThread %ld, %ld", (*my_pair).i, (*my_pair).j);
return NULL;
}
Number I am getting and it is also random.
Thread 0,2
Thread 1,2
Thread 2,3
Thread 2,3
Thread 2,3
Thread 2,3
am i passing the struct wrong ?
That is because you are passing the same pointer to all pthreads.
When you invoke pthread_create(..., (void*) pair) you are passing the pointer to the new thread, but in the next iteration you are overwriting that memory (potentially before the new thread has extracted those values).
long thread_cmp_count = (long)n*(n-1)/2;
long t,index = 0;
struct Pairs *pair;
cmp_thread = malloc(thread_cmp_count*sizeof(pthread_t));
for(thread = 0;(thread < thread_cmp_count); thread++){
for(t = thread+1; t < n; t++){
// allocate a separate pair for each thread
pair = malloc(sizeof(struct Pairs));
(*pair).i = thread;
(*pair).j = t;
pthread_create(&cmp_thread[index++], NULL, Compare, (void*) pair);
}
}
for(thread= 0;(thread<thread_cmp_count); thread++){
pthread_join(cmp_thread[thread], NULL);
}
free(cmp_thread);
.
void* Compare(void* pair){
struct Pairs *my_pair = (struct Pairs*)pair;
printf("\nThread %ld, %ld", (*my_pair).i, (*my_pair).j);
// free that memory after it has been used
free (pair);
return NULL;
}
Problem solved. Problem was with overlap. using pointer as an array of type struct Pairs it is solved
Here is the correct code
long thread_cmp_count = (long)n*(n-1)/2;
long t,index = 0;
Pair * pair;
pair = malloc(thread_cmp_count*sizeof(Pair));
free(thread_handles);
thread_handles = malloc(thread_cmp_count*sizeof(pthread_t));
for(thread = 0;(thread < n-1); thread++){
for(t = thread+1; t < n; t++){
(pair+index)->i = thread;
(pair+index)->j = t;
pthread_create(&thread_handles[index], NULL, Compare, (void*) (pair+index));
index++;
}
}
for(thread= 0;(thread<thread_cmp_count); thread++){
pthread_join(thread_handles[thread], NULL);
}
free(thread_handles);
And the function Compare
void* Compare(void* pair){
long t,i,j;
Pair *my_pair = (Pair*)pair;
i = my_pair->i;
j = my_pair->j;
printf("\n..................................................................");
if((x_array[i] < x_array[j])&&(x_array[i] != x_array[j])){
w_array[i] = 0;
printf(
"\nThread T(%ld,%ld)"
" compares x[%ld] = %ld and x[%ld] = %ld,"
" and writes 0 to w[%ld]", i, j,
i,x_array[i],
j,x_array[j],
i);
}
else if((x_array[i] > x_array[j])&&(x_array[i] != x_array[j])){
w_array[j] = 0;
printf(
"\nThread T(%ld,%ld)"
" compares x[%ld] = %ld and x[%ld] = %ld,"
" and writes 0 to w[%ld]", i, j,
i,x_array[i],
j,x_array[j],
j);
}
else
return NULL;
return NULL;
}

Resources