I have a file.txt with the following values: 1234 567 8910
I want to create a program in c , that creates x number of child threads with x being the number of lines in "file.txt". The child thread receives the line so it splits the line into digits and stores them in an array.
Then I want to create y number of grandchild threads under each child thread with y being the number of digits in that child thread array or received line value and pass each grandchild thread a single digit.
For example, for the above file.txt, my parent thread in main() will create 3 child threads. The first child thread will receive "1234", second "567", third "8910". Then the first child will create 4 grandchild threads and pass the first grandchild thread "1", second "2", third "3", fourth "4". Similarly, the second child will create 3 grandchild threads and pass the "5", "6", "7" digits. And lastly, the third child will create 4 grandchild threads and pass the "8", "9", "1", "0" digits.
I want to pass all these values using multi-threading in parallel. I am able to get everything working fine till the child thread, and I am able to create the right amount of grandchild threads, but I am unable to pass them the values. Any help and guidance are much appreciated.
Here is my code: (please guide me to fix it)
#include <iostream>
#include <pthread.h>
#include <math.h>
#include <fstream>
#include <sys/wait.h>
#include <cstdlib>
#include <unistd.h>
using namespace std;
struct info {
int* digit = new int;
int* totalDigits = new int;
};
struct grandchildThreadData {
int GCTDdigit;
int GCTDgrandchildIndex;
int GCTDchildIndex;
info* GCTDinfo = new info;
info* GCTDparentInfo = new info;
};
struct childThreadData {
long int CTDlineValue;
int CTDchildIndex;
info* CTDinfo = new info;
};
// thread declaration
void* childThread(void*);
void* grandchildThread(void*);
// function to convert and store line to digits
int* digitSeparator(long int);
// MAIN PROGRAM
int main() {
// FILE OPENING
int totalLines{0};
ifstream file1("file.txt"), file2("file.txt");
string temp;
while (getline(file1, temp)) {
totalLines ;
}
file1.close();
long int* valueOnLine = new long int[totalLines];
int i =0;
while (!file2.eof()) {
file2 >> valueOnLine[i];
i ;
}
file2.close();
// FILE CLOSING
// THREAD START
static struct info* mainInfo = new info[totalLines];
pthread_t* child = new pthread_t[totalLines];
// will be used to pass values to child
static struct childThreadData* Carg = new childThreadData[totalLines];
// Creating Childthreads
for (int i = 0; i < totalLines; i ) {
Carg[i].CTDinfo[i] = mainInfo[i];
Carg[i].CTDchildIndex = i;
Carg[i].CTDlineValue = valueOnLine[i];
if (pthread_create(&child[i], nullptr, childThread, &Carg[i])) {
fprintf(stderr, "Error creating thread\n");
return 1;
}
}
// Joining Childthreads
for (int i = 0; i < totalLines; i ) {
if (pthread_join(child[i], nullptr)) {
fprintf(stderr, "Error joining thread\n");
return 2;
}
}
delete[] valueOnLine;
delete[] child;
delete[] Carg;
return 0;
}
void* childThread(void* i) {
struct childThreadData* CTptr = (struct childThreadData*)i;
int totalDigits = log10((float)CTptr->CTDlineValue) 1;
int* numberArray = digitSeparator(CTptr->CTDlineValue);
// THIS LINE WILL PUT TOTAL DIGITS INTO mainInfo
CTptr->CTDinfo[CTptr->CTDchildIndex].totalDigits[0] = totalDigits;
static struct info* childInfo = new info[totalDigits]; // This can be used to print modified info in grandchild
pthread_t* grandchild = new pthread_t[totalDigits];
static struct grandchildThreadData* GCarg = new grandchildThreadData[totalDigits];
// THIS LINE WILL PUT EACH DIGIT ON CORRECT LOCATION of mainInfo
for (int i=0; i< totalDigits; i ) {
CTptr->CTDinfo[CTptr->CTDchildIndex].digit[i] = numberArray[i];
}
// GRANDCHILD THREAD
for (int i = 0; i < totalDigits; i ) {
GCarg[i].GCTDinfo[i] = childInfo[i]; // grandchild to child communication but does not work
// or
GCarg[i].GCTDparentInfo[i] = CTptr->CTDinfo[i]; // grandchild to parent communication but does not work
GCarg[i].GCTDgrandchildIndex = CTptr->CTDchildIndex; // Here CTptr->CTDchildIndex should pass 0, 1, 2 to grandchild but I get different values
GCarg[i].GCTDchildIndex = i; // This line works fine for some reason
GCarg[i].GCTDdigit = CTptr->CTDinfo[CTptr->CTDchildIndex].digit[i]; // This line should pass the correct digit, but again, I am getting different results in grandchild
if (pthread_create(&grandchild[i], nullptr, grandchildThread, &GCarg[i])) {
fprintf(stderr, "Error creating thread\n");
}
}
//Joining GrandChildthreads
for (int i = 0; i < totalDigits; i ) {
if (pthread_join(grandchild[i], nullptr)) {
fprintf(stderr, "Error joining thread\n");
}
}
return nullptr;
}
void* grandchildThread(void* i) {
struct grandchildThreadData* GCTptr = (struct grandchildThreadData*)i;
// THIS LINE SHOULD PRINT THE DIGIT
cout << GCTptr->GCTDdigit;
return nullptr;
}
int* digitSeparator(long int number) {
int totalDigits = log10((float)number) 1;
int* separatorPtr = new int[totalDigits];
int j = 0;
for (int i = totalDigits - 1; i >= 0; i--) {
long int divisor = pow((float)10, i);
long int digit = number / divisor;
number -= digit * divisor;
separatorPtr[j] = digit;
j ;
}
return separatorPtr;
}
CodePudding user response:
The issue was caused by using static structs:
So, if we replace:
static struct childThreadData* Carg = new childThreadData[totalLines];
static struct grandchildThreadData* GCarg = new grandchildThreadData[totalLines];
with:
childThreadData* Carg = new childThreadData[totalLines];
grandchildThreadData* GCarg = new grandchildThreadData[totalLines];
It will work fine.
CodePudding user response:
This is not an exhaustive list of the problems in the program but it deals some fundamental problems.
Your program does not check if
file.txt
is successfully opened. If it's not, the program will continue to run until it gets a signed integer overflow - which means that the program has undefined behavior.If the file is successfully opened, you'll run into heap-buffer-overflow
// Creating Childthreads for(int i = 0; i < totalLines; i ) { Carg[i].CTDinfo[i] = mainInfo[i]; // <- here
That's because
CTDinfo[i]
is out of bounds wheni > 0
.CTDinfo
is a pointer to one singleinfo
- nottotalLines
ofinfo
s.Same thing below.
CTDinfo
can't be treated as an array since it's a pointer to a singleinfo
- anddigit
is a pointer to a singleint
- not an array ofint
.// THIS LINE WILL PUT EACH DIGIT ON CORRECT LOCATION of mainInfo for(int i = 0; i < totalDigits; i ) { CTptr->CTDinfo[CTptr->CTDchildIndex].digit[i] = numberArray[i]; }
Suggestions:
- Write a much smaller program to get the hang of threading.
- Write a much smaller program to learn how to build up very complicated structures (if you are really required to do so). Use C classes, like
std::vector
. I doubt this program would need a singlenew
/new[]
if you replaced all the manual memory management with standard C containers. Things likeinfo
looks like there's been a misunderstanding. There is no reason why pointers should be used here:struct info { int* digit = new int; int* totalDigits = new int; };
- Use
std::thread
and its support functions and classes instead of the platform specific C API inpthread
.