I'm trying to implement a shuffling technique based on a random time so that it is possible for one message to overtake the next message and becomes shuffled. I have an original message that is separated into chunks per thread. Each thread sleeps and prints out the chunk afterwards.
original_message > grab a slice of original_message > deal with it in another thread > grab another slice > deal with it in another NEW thread while the other thread may/may not be running > and repeat until all slice is taken.
However, sometimes the output is the same and that they do not output the after the sleep one by one e.g. the one with 0 seconds sleep comes out first.... How can I create a new thread with its own stack so that it does not share those variables. I'm not sure mutex lock will suffice because it may affect the sleep timings. What can I do to fix it?
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
struct argsparam {
int sleep;
char split_message[5];
};
void* sleep_shuffle(void *arguments){
struct argsparam *args = arguments;
sleep(args->sleep);
printf("shuffled message: %s\n", args->split_message);
}
int main(){
struct argsparam args;
pthread_t sleeppt[4];
time_t t;
srand((unsigned) time(&t));
char original_message[20] = "1234567890abcdefghij";
for(int i=0; i<4; i++){
memcpy(args.split_message , original_message+(i*5), 5);
args.split_message[5] = '\0'; //null terminator
args.sleep = rand() % 5;
printf("message: %s and time: %d\n", args.split_message, args.sleep);
if(pthread_create( &sleeppt[i], NULL, sleep_shuffle, (void *)&args) != 0)
printf("Error in creating thread!");
}
for(int i=0; i<4; i++){
pthread_join(sleeppt[i], NULL);
}
}
You're passing the same copy of args to each thread, overwriting the previous value before calling the next thread, so what each thread reads is dependent on the timing of each thread.
Create an array of struct argsparam, one for each thread, then pass in the pointer to the appropriate instance. That way they won't interfere with each other.
int main(){
// an array of args
struct argsparam args[4];
pthread_t sleeppt[4];
time_t t;
srand((unsigned) time(&t));
char original_message[20] = "1234567890abcdefghij";
for(int i=0; i<4; i++){
// assign to a specific array instance for each thread
memcpy(args[i].split_message , original_message+(i*5), 5);
args[i].split_message[5] = '\0'; //null terminator
args[i].sleep = rand() % 5;
printf("message: %s and time: %d\n", args[i].split_message, args[i].sleep);
if(pthread_create( &sleeppt[i], NULL, sleep_shuffle, (void *)&args[i]) != 0)
printf("Error in creating thread!");
}
for(int i=0; i<4; i++){
pthread_join(sleeppt[i], NULL);
}
}
Sample output (yours may vary):
message: 12345 and time: 0
message: 67890 and time: 3
message: abcde and time: 2
message: fghij and time: 1
shuffled message: 12345
shuffled message: fghij
shuffled message: abcde
shuffled message: 67890
Also, your split_message array isn't big enough to hold the string you're copying in. You need a total of 6 bytes, for for each of 5 characters and one for the null terminator.
struct argsparam {
int sleep;
char split_message[6];
};
You're "lucky" that you're not stepping on memory you shouldn't due to structure padding.
First, the size of the "split_message[5] of struct argsparam" array is incorrect.
Second, why not use "args" as an array?
--- orig.c 2017-06-14 03:18:25.569775282 +0900
+++ dest.c 2017-06-14 03:16:52.989777492 +0900
## -6,7 +6,7 ##
struct argsparam {
int sleep;
- char split_message[5];
+ char split_message[6];
};
void* sleep_shuffle(void *arguments){
## -16,7 +16,7 ## void* sleep_shuffle(void *arguments){
}
int main(){
- struct argsparam args;
+ struct argsparam args[4];
pthread_t sleeppt[4];
time_t t;
int i;
## -25,12 +25,12 ## int main(){
char original_message[20] = "1234567890abcdefghij";
for(i=0; i<4; i++){
- memcpy(args.split_message , original_message+(i*5), 5);
- args.split_message[5] = '\0'; //null terminator
- args.sleep = rand() % 5;
+ memcpy(args[i].split_message , original_message+(i*5), 5);
+ args[i].split_message[5] = '\0'; //null terminator
+ args[i].sleep = rand() % 5;
- printf("message: %s and time: %d\n", args.split_message, args.sleep);
- if(pthread_create( &sleeppt[i], NULL, sleep_shuffle, (void *)&args) != 0)
+ printf("message: %s and time: %d\n", args[i].split_message, args[i].sleep);
+ if(pthread_create( &sleeppt[i], NULL, sleep_shuffle, (void *)(args + i)) != 0)
printf("Error in creating thread!");
}
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've been trying to use Pthreads in a program to count the 3's in a 3000000 element int array, and when it runs sequentially without using pthreads, it works perfectly.
Using pthreads leads to a segmentation fault and i can't figure out why. the execution stops when each thread reaches around 300000 iteration in case of 4 threads on a 8gb of RAM and 256K L2 cache.
Here is my code
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <pthread.h>
#define LENGTH 3000000
#define NUM_THREADS 4
int countarr[128];
int* array;
struct Op_data{
int start_index;
int count_index;
int CHUNK;
int ID;
};
void* count3s(void* data) // you need to parallelize this
{
struct Op_data *info;
info = (struct Op_data *) data;
int count_i = info -> count_index;
int i = info->start_index;
int CHUNK = info -> CHUNK;
printf("Thread data:\nCOUNT_INDEX:\t\t%d\nSTART_INDEX:\t\t%d\nCHUNK_SIZE:\t\t%d\n",count_i,i,CHUNK);
int c = 0;
struct timeval t1, t2;
gettimeofday(&t1, NULL);
for(i;i<i+CHUNK;i++)
{
if(array[i]==3)
{
c++;
}
}
countarr[count_i] = c;
gettimeofday(&t2, NULL);
double t = (t2.tv_sec - t1.tv_sec) + (t2.tv_usec - t1.tv_usec ) / 1000000.0;
printf("execution time = %f seconds\n",t);
}
int main(int argc, char * argv[])
{
int i = 0;
int ok = 0;
int count=0;
array = malloc(LENGTH * sizeof(int));
// initialize the array randomly. Make sure the number of 3's doesn't exceed 500000
srand(12);
for(i= 0;i<LENGTH;i++)
{
array[i]=rand()%10;
if(array[i]==3)
{
ok++; // keep track of how many 3's are there, we will use this later to confirm the correctness of the code
if(ok>500000)
{
ok=500000;
array[i]=12;
}
}
}
pthread_t threads[NUM_THREADS];
struct Op_data* t_data[NUM_THREADS];
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
int rc;
int CHUNK = LENGTH/NUM_THREADS;
for(int t=0;t<NUM_THREADS;t++)
{
t_data[t] = (struct Op_data*) malloc(sizeof(struct Op_data));
t_data[t] -> start_index = t*CHUNK;
t_data[t] -> count_index = t*(128/NUM_THREADS);
t_data[t] -> CHUNK = CHUNK;
t_data[t] -> ID = t;
rc = pthread_create(&threads[t], &attr, count3s, (void *)t_data[t]);
if (rc) {
printf("Error:unable to create thread,%d\n",rc);
exit(-1);
}
printf("Thread (%d) has been created.\n",t);
}
for( int g = 0; g < NUM_THREADS; g++ ) {
rc = pthread_join(threads[g], NULL);
if (rc) {
printf("Error:unable to join,%d\n",rc);
exit(-1);
}
}
pthread_attr_destroy(&attr);
for(int x=0;x<NUM_THREADS;x++)
{
count += countarr[x*(128/NUM_THREADS)];
}
if( ok == count ) // check if the result is correct
{
printf("Correct Result!\n");
printf("Number of 3`s: %d\n_________________________________\n",count);
}
else
{
printf("Wrong Result! Your count:%d\n",count);
printf("The correct number of 3`s is: %d\n",ok);
}
pthread_exit(NULL);
return 0;
}
for(i;i<i+CHUNK;i++)
Since i will always be less than i + CHUNK (unless it overflows), this loop will overrun the bounds of the array.
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);
}
I'm trying to solve a small problem of synchronization. but when I join the threads i get segment fault of the fifth iteration! If i only create 4 threads works perfect.
Here I leave the code with some basics of what to do the thread.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
sem_t HackersEmploy_Counter;
int hackerOnBoat, employOnBoat, B, b, hackerResagado, employResagado;
sem_t Board;
int onBoatId[4];
char onBoatType[4];
sem_t Bote;
typedef struct{
FILE* log;
int ID;
}param;
void* HackerArrive(void* para){
param* var = (param*) para;
printf("Create Hacker %i\n", var->ID-1);
pthread_exit(0);
}
void* EmployeeArrive(void* para){
param* var = (param*) para;
printf("Create Employee %i\n", var->ID-1);
pthread_exit(0);
}
int main(int argc, char **argv) {
sem_init(&HackersEmploy_Counter,0,1);
sem_init(&Bote,0,4);
sem_init(&Board,0,1);
FILE* log;
log = fopen("result_simulacion.txt", "w");
int E, e=1, H, h=1, i, r;
hackerOnBoat=0; employOnBoat=0; b=1; hackerResagado=0; employResagado=0;
for (i=1; i<argc; i++){
if (strcmp(argv[i],"-h")==0){
i++;
H = atoi(argv[i]);
}
if (strcmp(argv[i],"-e")==0){
i++;
E = atoi(argv[i]);
}
if (strcmp(argv[i],"-b")==0){
i++;
B = atoi(argv[i]);
}
}
pthread_t* bank = (pthread_t*) malloc( (E+H) * sizeof (pthread_t*));
param* var = (param*) malloc( (E+H) + sizeof (param*));
for (i=0; i<H+E; i++){
r = rand() % 2;
if (r==0){
if (h<=H){
var[i].log = log;
var[i].ID = h;
pthread_create(&bank[i], NULL, HackerArrive, (void*) &var[i]);
h++;
}else{
var[i].log = log;
var[i].ID = e;
pthread_create(&bank[i], NULL, EmployeeArrive, (void*) &var[i]);
e++;
}
}else{
if (e<=E){
var[i].log = log;
var[i].ID = e;
pthread_create(&bank[i], NULL, EmployeeArrive, (void*) &var[i]);
e++;
}else{
var[i].log = log;
var[i].ID = h;
pthread_create(&bank[i], NULL, HackerArrive, (void*) &var[i]);
h++;
}
}
}
for (i=0; i<E+H; i++){
pthread_join(bank[i], NULL);
printf("join %i\n", i);
}
return 0;
}
run with: ./work -h 4 -e 0 -b 1
them run with: ./work -h 5 -e 0 -b 1
if they increase the value of "-h" more than 4 receive segmentation fault
Why this?
The allocation for your array of pthread_ts isn't quite right. You want to allocate storage for an array of pthread_t instances but are currently only allocating space for pointers.
By not allocating space for the correct type, you risk writing beyond the end of your allocated memory when you later write to this array. This has undefined consequences; in this case you're likely to over-write memory used by other parts of your program. This may well cause a segfault.
You should change the allocation as follows
pthread_t* bank = malloc((E+H) * sizeof(*bank));
The same issue applies to the param array var which should be allocated like
param* var = malloc((E+H) + sizeof(*var));
Note that it'd be good practice for you to free these arrays later in your program
for (i=0; i<E+H; i++){
pthread_join(bank[i], NULL);
printf("join %i\n", i);
}
free(bank);
free(var);
Please be more careful reading your code. This:
param* var = malloc((E+H) + sizeof(*var));
should be this:
param* var = malloc((E+H) * sizeof(*var));
// ^
Your code works (or at least, doesn't crash) for me after this change:
paul#local:~/src/c/scratch$ ./thread -h 2 -e 2 -b 2
Create Employee 0
Create Hacker 1
Create Employee 1
Create Hacker 0
join 0
join 1
join 2
join 3
paul#local:~/src/c/scratch$
Using a tool like valgrind would have helped you track this one down in minutes.
As mentioned in my other comment, you should check the return every single time you call functions like malloc(), fopen(), pthread_create(), pthread_join(), and so on, otherwise you have absolutely no idea whether you're ignoring important errors your functions are trying to tell you about.
I am trying to write a program which gets input files and prints included items into the screen by threads. However, last thread doesn't give any output unexpectedly. I couldn't figure out what the problem is. I am waiting for your help.
Each thread gets 3 parameters :inputFile1, inputFile2 and targetBuf(lets say it is sequence number.) Files are sorted, I just simply try to print their union in order. Only positive numbers are printed.
Command line : merge N outfile file1 file2 file3 .... fileN
N is the number of input files.
If I give 2 input files (means 1 thread), it works. If I give 4 files, then 1st thread give output, 2nd one does not. If I give 6 input files, then 1st and 2nd threads give output but 3rd doesn't.
There are two structs in header file. I pasted them below.
//thread information
struct threadInfo{
pthread_t tid;
pthread_attr_t attr;
};
//Beginning thread input
struct beginThreadInput{
FILE **inputFile1, **inputFile2;
int targetBuf;
};
typedef struct threadInfo THREADINFO;
typedef struct beginThreadInput BEGINT_INPUT;
Main File Code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h> //for O_ constants
#include <sys/stat.h>
#include <pthread.h> /* thread library */
#include "merge.h"
int main(int argc, char** argv){
int i, k, N;
/***FILE INITIALIZATION***/
FILE *output;
N = atoi(argv[1]);
output = fopen(argv[2], "w");
FILE **inputFileList = ((FILE**)malloc (N * sizeof(FILE*)));
printf("int N is %d\n", N);
for(i = 0; i<N; i++){
inputFileList[i] = fopen(argv[i + 3], "r");
}
//START THREADS
BEGINT_INPUT **threadInputList = ((BEGINT_INPUT**) malloc ( (N/2)* sizeof(BEGINT_INPUT*)));
THREADINFO **threadInfoList = ((THREADINFO**) malloc ( (N/2) * sizeof(THREADINFO*)));
for(i = 0; i< N/2 ; i++){
threadInputList[i] = (BEGINT_INPUT *) malloc (sizeof(BEGINT_INPUT));
threadInfoList[i] = (THREADINFO *) malloc (sizeof(THREADINFO));
}
pthread_t tid;
pthread_attr_t attr;
for(i = 0, k = 0; i < (N/2); i++){
threadInputList[i]->inputFile1 = &(inputFileList[k]);
threadInputList[i]->inputFile2 = &(inputFileList[++k]);
threadInputList[i]->targetBuf = i;
pthread_attr_init(&(threadInfoList[i]->attr));
pthread_create(&(threadInfoList[i]->tid), &(threadInfoList[i]->attr), runBeginningThreads, (void*)threadInputList[i]);
}
pthread_join((threadInfoList[[(N/2)-1]]->tid), NULL);
for(i = 0; i<N; i++){
fclose(inputFileList[i]);
}
}
void *runBeginningThreads(void *input){
BEGINT_INPUT *myInput = (BEGINT_INPUT *)input;
int first = -1, second = -1, iseof;
printf("Thread number %d\n", myInput->targetBuf);
while((second > -2) && (first > -2)){
//read integer values from files
if(first == -1){
iseof = fscanf(*(myInput->inputFile1), "%d", &first);
if(iseof == EOF){
first = -2; //means end of file
}
else if(first < 0)
first = -1; //means waiting for an integer
}
if(second == -1){
iseof = fscanf(*(myInput->inputFile2), "%d", &second);
if(iseof == EOF){
second = -2;
}
else if(second < 0)
second = -1;
}
//print smaller one
if((first != -1) && (second != -1)){
if(((first < second) || (second == -2)) && (first != -2)){
printf("%d\n", first);
first = -1;
}
else if(second != -2){
printf("%d\n", second);
second = -1;
}
}
}
}
The main problem might be that you only wait for one thread to finish, before you close all files and then exit from the program.
There are a few other extra complications in your program, that could probably be simplified. I mean that you use extra pointer indirection when you don't really need it.
Here's a little simpler version, not using extra pointer-to-pointers where none are needed:
struct beginThreadInput{
FILE *inputFile1, *inputFile2;
int targetBuf;
};
/* ... */
int main(int argc, char** argv){
/* ... */
BEGINT_INPUT *threadInputList = malloc ( (N/2)* sizeof(BEGINT_INPUT));
THREADINFO *threadInfoList = malloc ( (N/2) * sizeof(THREADINFO));
pthread_t tid;
for(i = 0, k = 0; i < (N/2); i++){
threadInputList[i].inputFile1 = inputFileList[k];
threadInputList[i].inputFile2 = inputFileList[++k];
threadInputList[i].targetBuf = i;
pthread_create(&(threadInfoList[i].tid), NULL, runBeginningThreads, &(threadInputList[i]));
}
for(i = 0; i< N/2 ; i++){
pthread_join((threadInfoList[i]->tid), NULL);
}
/* ... */
/* While not strictly needed, you should make it a good
habit of freeing all you allocate */
free(threadInfoList);
free(threadInputList);
return 0; /* You missed this */
}
I solve my question in the following way. As it is seen above, I open the files in main function, then pass them into corresponding threads. I have changed this way and passed the names of the files into threads and open related files in them.
Additionally, while passing files, I was making mistakes, its code is below
threadInputList[i]->inputFile1 = &(inputFileList[k]);
threadInputList[i]->inputFile2 = &(inputFileList[++k]);
This lines are run in a loop. This causes an input sequence like the following ([0,1], [1,2], [2,3], [3,4] ...) becuase I increment k only one time.However, each thread takes two of inputFiles. So the correct code is this:
threadInputList[i]->inputFile1 = &(inputFileList[k++]);
threadInputList[i]->inputFile2 = &(inputFileList[k++]);
I want to point out an issue. I fixed this code for file names, not FILE pointer variables as it is posted there. But to make it clear, I fixed the bug on a code posted there. Thanks for your help, everybody