Advertisement

Starting a new c++ thread

Started by November 27, 2024 01:08 PM
7 comments, last by Calin 1 hour, 19 minutes ago

I hope creating several discussions in a short time period is not regarded as an abuse. I have another question, codeproject.com forums are down and I have nowhere to go for help.

I'm looking to find out how you can start a new thread in c++ and check back later to see if the thread is done working and pick up the result. The internet example I found looks a lot like running a function in the same thread rather then a new thread

(I modified the example to fit what I need)

void foo(int A, int B, int * Result)
{

* Result = A + B;
}

int main()
{
int Result;
thread th1(foo, 3,4,&Result);
th1.join(); // I don't want to wait;
cout << "work done the result is ";
cout << Result;
}

My project`s facebook page is “DreamLand Page”

#include <atomic>
#include <vector>
#include <chrono>
#include <thread>
#include <mutex>
#include <string>
#include <iostream>
#include <chrono>
using namespace std;

void thread_func(atomic_bool& stop, atomic_bool &thread_done, vector<string>& vs, mutex& m)
{
	thread_done = false;

	while (!stop)
	{
		m.lock();
		vs.push_back("test");
		m.unlock();
	}

	thread_done = true;
}



int main(void)
{
	atomic_bool stop = false;
	atomic_bool thread_done = false;

	mutex m;
	vector<string> vs;
	thread t(thread_func, ref(stop), ref(thread_done), ref(vs), ref(m));

	auto start_time = std::chrono::system_clock::now();
	auto end_time = start_time + std::chrono::seconds(2);

	while (!stop)
	{
		auto curr_time = std::chrono::system_clock::now();

		if (curr_time >= end_time)
			stop = true;

		cout << "Printing log:" << endl;
		
		m.lock();

		for (vector<string>::const_iterator ci = vs.begin(); ci != vs.end(); ci++)
			cout << *ci << endl;

		vs.clear();

		cout << endl;

		m.unlock();
	}

	while (!thread_done)
	{
		cout << "Waiting for thread" << endl;
		// draw graphics
	}

	cout << "Joining" << endl;

	t.join();

	cout << "Done" << endl;

	return 0;

}

Advertisement

In this code it looks like the thread is starting, doing a simple math operation that finishes almost instantly. The join() function blocks execution on the main thread until the thread has finished and the result is ready.

To keep the main thread running don't call join() until after the work is done. You could have a shared value to signal it is done, or a synchronization primitive like std::atomic if you need extra functionality to keep threads from fighting over memory.

A typical threading learning exercise is to start threads that loop by outputting their thread number and the loop count then sleeping for a moment, while the main thread is looping on something else. You can start several of these worker threads set to run for five seconds or so, then have the main loop run for six or seven. The next learning step is to have an array in the main thread for each worker thread status, have each worker thread set their status when done, and having the main thread occasionally loop through the array to see if all the workers have set their status; when each thread finishes you can join back with it to clean up the resource, until all are done.

Eventually your main thread needs to release the thread resources either by joining back up or detaching the thread. Doing neither can result in zombie threads, technically dead because they have finished their work but not fully dead because their owning process hasn't dealt with their cleanup.

A better way to wait on a result from a thread is std::future. See https://en.cppreference.com/w/cpp/thread/future. You launch an future as async when you want the work to begin, and later, when you need to value, you request it.

// can now use a normal return value
int foo(int A, int B)
{
    return A + B;
}

// start doing the async work
std::future<int> f2 = std::async(std::launch::async, &foo);

// do other work
...

// get the result - will block until the thread finished
const int result = f2.get();

Calin said:
The internet example I found looks a lot like running a function in the same thread rather then a new thread

Your code does use two threads, it's just that the main thread does nothing but waiting, so the multithreading is pointless.

The simplest way to change this is probably:

void foo(int A, int B, int * Result)
{

* Result = A + B;
}

int main()
{
int Result;
thread th1(foo, 3,4,&Result); // spawned thread is working...

int Result2;
foo
(5,6,&Result2); // main thread is working in prallel...

th1.join(); // main thread is done and waits for the spawned thread to finish as well. spawned thread is destroyed.

cout << "work done. Result: "<< Result << " Result2: << Result2;
}

Your code does use two threads, it's just that the main thread does nothing but waiting, so the multithreading is pointless.

I know that. I thought thread has a finish flag that you can check.

Here is a more complex example.

enum Progress
{
    StartThr,
    CheckIfFinished,
    End
};
int TestF(int A,int B, int * Result)
{
    *Result = A + B;
}
Progress Prg;
int Result;
void GameUpdate()
{
    switch (Prg)
    {
    case Progress::StartThr:
        thread th1(TestF, 3,4,&Result);
        Prg = Progress::CheckIfFinished;
        break;
    case Progress::CheckIfFinished:
        if (th1.Finished)
        {
            Prg = Progress::End;
            break;
        }
        else
        {
            break;
        }
    case Progress::End:
        // use Result
    }
}

My project`s facebook page is “DreamLand Page”

Advertisement

Calin said:
I thought thread has a finish flag that you can check.

It has not, but there are many ways to communicate across multiple threads:
Atomics. E.g. thread A sets an atomic flag which other threads can check.
std::mutex can be used to define a critical code section which only one thread at a time can run.
std::condition_variable can be used to notify other threads, or to wake them up when they sleep but new work is ready, fopr example.

That's all i've personally used and needed so far. Idk about newer features such as std::future.

However, keep in mind that many of those language features are about creating new threads on demand.
For games this can be actually too slow, as creating threads is very expensive.
The better way is to create a pool of persistent worker threads just once at application launch, then using those same threads for all work that comes up. Beside the work management itself, this requires to set the threads to sleep if no work is pending, so they do not maximize CPU utilization just from constantly polling for pending work.

It's not easy to find related tutorials. The only one i know is this: https://wickedengine.net/2018/11/simple-job-system-using-standard-c/

This is not an ideal solution, but surely much better than creating threads on demand if you nedd many threads. Good enough for a start, if you're interested.
There are also related libraries, e.g. Intels TBB, but i have never used any of these.
I've heard future C++ standard may add those things, so maybe it's worth to wait.

but there are many ways to communicate across multiple threads

This will take me a while. Things are way more complicated than what I initially thought they would be.

Thank you guys.

My project`s facebook page is “DreamLand Page”

Advertisement