I'm trying to learn a bit more about the properties about Threads in c++, more accurate: Posix Threads. I constructed a little program that let's you write a total number of string of certain length into a big char* cstr that holds all of the strings, intended to be used in another c program.
I've noticed that I can get a very good result when using 2 Threads to speed the generation up, but anything past that actually slows the program more down than even using 1 thread. Now I'm not sure whether my approach is wrong i.e. using strcpy() to get the strings into my cstr or using more than 2 threads is just not worth it. Could their be risk involved in writing to a global char pointer?
CreateCString() creates the requested number of Threads, assigns them their workspace via the struct, runs the corresponding function and then waits for them to finish.
struct MyArgs {
long start;
long end;
};
void CreateCString() {
pthread_t threads[NUM_THREADS];
MyArgs args[sizeof(MyArgs) * NUM_THREADS];
int prev = 0;
int add = TOTAL/ NUM_THREADS;
int prev2 = add;
for (int i = 0; i < NUM_THREADS; i++)
{
args[i].start = prev;
args[i].end = prev2;
prev2 += add;
prev = args[i].end;
pthread_create(&threads[i], NULL, myfunc, &args[i]);
cout << "args start von " << i << ": " << args[i].start << endl;
cout << "args end von " << i << ": " << args[i].end << endl;
}
for (int i = 0; i < NUM_THREADS; i++)
{
pthread_join(threads[i], NULL);
}
}
The called function of all Threads, where the needed parameters are being assigned to the real function.
void* myfunc(void* p) {
MyArgs* p_arg = (MyArgs*)p;
int start = p_arg->start;
int end = p_arg->end;
addString(p_arg->start, p_arg->end);
pthread_exit(NULL);
}
The actual meat and potatoes. The function scales to the requested String Length and gives each Thread their own space where they can copy the results into.
void addString(int start, int end) {
for (int i = start; i < end; i++)
{
strcpy((cstr + i * STRING_LENGTH), generateRandomString(STRING_LENGTH).c_str());
}
}
Method used for random String Generation
std::string generateRandomString(const int max_length) {
using namespace std;
string possible_characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
random_device rd;
mt19937 engine(rd());
uniform_int_distribution<> dist(0, possible_characters.size() - 1);
string ret = "";
for (int i = 0; i < max_length; i++) {
int random_index = dist(engine); //get index between 0 and possible_characters.size()-1
ret += possible_characters[random_index];
}
return ret;
}
Main();
#define NUM_THREADS 2
#define STRING_LENGTH 8
int TOTAL;
char* cstr;
int main()
{
cout << "total strings?"; cin >> TOTAl;
cstr = new char[TOTAL * (STRING_LENGTH + 1)];
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
CreateCString();
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "Time elapsed in total = " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << "[micros]" << std::endl;
std::cout << "Time elapsed in total = " << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() << "[ms]" << std::endl;
std::cout << "Time elapsed in total = " << std::chrono::duration_cast<std::chrono::seconds>(end - begin).count() << "[s]" << std::endl;
cout << "----------------------------------------------------------------------" << endl;
cout << endl;
delete[] cstr;
}
Is this even the right approach if we are going for relative high speed? How else could we fill cstr with all the wanted strings? Or is it just not worth it to use more than maybe 2 Threads for high numbers? (~million)
Here are some Example times that I'm getting when generating 1000000 Strings using different amount of threads.
Total Strings: 1 000 000
Number of Threads: 1
Total time: 19s
Total Strings: 1 000 000
Number of Threads: 2
Total time: 10s
Total Strings: 1 000 000
Number of Threads: 3
Total time: 9s
Total Strings: 1 000 000
Number of Threads: 4
Total time: 38s (This one makes me scratch my head)