I mean c++ thread.
cost in terms of cpu cycle, and space.
As I know no of program level(user level) thread connect with single system level thread(in single core cpu).
so some cost is involve to create this structure.
In a program I want to create and use multiple thread dynamically.
so if I am able to reuse thread then I don't need to generate new thread .
Yes. You can do anything in one thread -- the only limitation is that you can only do one thing at a time.
Multithreading in C++ is very tricky because it's very easy to screw up, and when you screw it up it causes extremely hard-to-find and hard-to-fix bugs.
Er... well... you just don't exit the thread. Threads remain "alive" until you exit... so just don't exit:
1 2 3 4 5 6 7
void yourThread()
{
doOneThing();
reuseToDoAnotherThing();
} // <- once we return, the thread closes, so don't return until you're done with the thread
Not to step on any ones toes, but it occurs to me that I can't ever remember writing something where I reuse threads*. So I decided to try my hand at a functional example. Sorry OP, but you didn't mention your preferred platform so I went with mine:
WinAPI threads instead of the much easier to use std::thread? INSANITY!
Also, the typical example of reusing threads is to have a thread pool -- where you have "jobs" that get added to a queue, and then a bunch of available threads that just pick them up and run them when they're able.
There are lots of threadpool libs out there... but here's a basic one I whipped up. Largely untested.
#include <functional> // function
#include <thread> // thread
#include <mutex> // mutex
#include <condition_variable> // condition_variable
#include <memory> // unique_ptr
#include <vector> // vector
#include <deque> // deque
class ThreadPool
{
private:
typedef std::mutex mutex;
typedef std::unique_lock<mutex> lock;
typedef std::unique_ptr<std::thread> threadPtr;
typedef std::function<void()> job;
std::vector<threadPtr> threads; // However many threads we want in this pool
std::deque<job> pendingJobs; // The jobs that are waiting to be performed by these threads
bool wantShutdown; // Flag to indicate we want to shutdown all threads
mutex jobMutex; // Mutex to guard the job queue and shutdown flag
std::condition_variable jobCV; // Condition Var to facilitate inter-thread notification
/////////////////////////////////////////////////
// Thread logic. IE: this is where the thread is "recycled"
void threadLoop()
{
while(true) // keep looping forever!
{
job j = nullptr; // the next job we are to perform
{
lock lk(jobMutex); // lock the mutex
// use CV to wait until we either want to shut down, or until there is at least 1 job availble
jobCV.wait(lk, [&]{ return wantShutdown || !pendingJobs.empty(); });
// If we want to shutdown, exit (and therefore shut down the thread)
if(wantShutdown)
return;
// otherwise, grab the next job and remove it from the queue
j = pendingJobs.front();
pendingJobs.pop_front();
} // <- unlocks the mutex
// if we have a job, do it
if(j)
j();
} // <- keep looping and performing jobs until shutdown
}
// no copying
ThreadPool(const ThreadPool&);
ThreadPool& operator = (const ThreadPool&);
public:
ThreadPool(int numthreads = 3)
: threads(numthreads)
, wantShutdown(false)
{
// ctor: just create our threads and get them started in that loop
for(auto& i : threads)
{
i = threadPtr( new std::thread( std::bind(&ThreadPool::threadLoop,this) ) );
}
}
~ThreadPool()
{
// dtor, shutdown all threads
{
lock lk(jobMutex); // lock the mutex
wantShutdown = true; // tell threads we want them to shutdown
pendingJobs.clear(); // clear all pending jobs that we didn't get to
} // (unlock mutex)
jobCV.notify_all(); // 'wake up' all threads that are currently waiting
// so that they can see we want to shut down
while(!threads.empty())
{
threads.back()->join(); // join thread (wait for it to close naturally)
threads.pop_back(); // and remove it from our list
} // loop until all threads are gone
}
void addJob(const job& j)
{
{
lock lk(jobMutex); // lock mutex
pendingJobs.push_back(j); // add a new job
} // (unlock)
jobCV.notify_one(); // 'wake up' one waiting thread so the job we just added will be picked up.
}
};
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
// Usage example
void job1()
{
//...
}
void job2()
{
//...
}
int main()
{
ThreadPool pool;
pool.addJob( &job1 ); // <- call job1 in the next available thread in the pool
pool.addJob( &job2 ); // <- call job2
// etc...
}
I post stuff on the forums because it's convenient. Posting it on github isn't convenient for me (I don't think I even have git installed -- or if I even have an account).
If you want to upload it for me, feel free. Anything I post on these boards can always be used as public domain unless I specifically say otherwise (which I likely never will).
ok done f2
tferminate called without an active exception
un f3
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
Process returned 255 (0xFF) execution time : 6.072 s
Press any key to continue.
reassigning a thread (or letting it be destructed), while the thread is joinable will result in std::terminate being called (ie, effectively crashing your program).
But again note that you are effectively creating a new thread and then move-assigning it. You are not reusing the same thread. Once the first thread is joined, it's done, it's gone forever.
Move-assignment on a thread is like move-assignment on a vector. The original vector is destroyed, and replaced with a completely new vector.
thread(f2); // <- this will create a whole new thread
There is no way to reassign a new entry point to a thread. If there were, there would be a function like this:
myThread.restart(f2);
But there is no such function because that's simply not how threads work. Once a thread has a function to run -- it runs it. And when it finishes that function, it is done. Period. The thread is effectively destroyed.
The only way to reuse the same thread is to make it so the thread's function never exits. My ThreadPool example illustrates how you can do that. You can have the thread go in a loop and wait for it to be assigned a new function to run.