cpp thread

I have few thread related q?

my q? is creating a thread is cost free if not then can I reuse cpp thread?
I don't understand your question.
is "cpp thread" the name of a thread?
What do you mean with cost free?
How do you plan to reuse the thread?
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 .

is creating a thread is cost free


Absolutely not.

can I reuse cpp 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.
can you give me a example how to reuse a thread.
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
#include <string>

#include <windows.h>
#include <process.h>

const std::string MutexName = "Mutex";
HANDLE GlobalMutexHandle = NULL;

void pause()
{
    std::cin.sync();
    std::cin.ignore();
}

void Thread(LPVOID arg)
{
    HANDLE LocalMutexHandle = NULL;
    int* ThreadArg = reinterpret_cast<int*>(arg);

    while(1)
    {
        WaitForSingleObject(GlobalMutexHandle, INFINITE);

        LocalMutexHandle = OpenMutexA(MUTEX_ALL_ACCESS, FALSE, MutexName.c_str());

        std::cout << "Work To Do: " << *ThreadArg << "\n";

        ReleaseMutex(LocalMutexHandle);
    }
}



int main()
{
    GlobalMutexHandle = CreateMutexA(NULL, TRUE, MutexName.c_str());
    int Arg = 0;

    _beginthread(Thread, 0, reinterpret_cast<void*>(&Arg));

    std::cout << "Press ctrl+c To Exit The Console\n";
    pause();

    while(1)
    {
        ReleaseMutex(GlobalMutexHandle);

        WaitForSingleObject(GlobalMutexHandle, INFINITE);
        GlobalMutexHandle = OpenMutexA(MUTEX_ALL_ACCESS, FALSE, MutexName.c_str());

        Arg++;

        pause();
    }

    CloseHandle(GlobalMutexHandle); ///NOT ACTUALLY CALLED.

    return 0;
}


*: Yes, I am aware that there is a cost to creating new threads. But it is marginal on modern PC systems.
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124


#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...
}
Disch, examples that large are worthy of preservation.
https://gist.github.com/ or https://github.com/cpluspluscom/dev-classes
Last edited on
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).
I can create a thread and store it in a container;
1
2
vector<thread*> v;
v.push_back(new thread());


assign a function to the thread
*v[0]=thread(f1);

next time when I want to use the thread, How to know thread is available to the next use;

I try to reuse the thread but it so me error(win7 code block ide).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<iostream>
#include<thread>
#include<chrono>
//#include<future>
#include<vector>
using namespace std;

void f2(){
cout<<"ok done f2"<<endl;

}

void f3(){
cout<<"fun f3";

}

int main(){
vector<thread*> v;
v.push_back(new thread());
*v[0]=thread(f2);
this_thread::sleep_for(chrono::seconds(1));
*v[0]=thread(f3);

v[0]->join();

return 0;
}




output


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.
Last edited on
@sujintag:

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).

You need to join threads before reassigning:

1
2
3
4
*v[0]=thread(f2);
// this_thread::sleep_for(chrono::seconds(1));  // <- don't just sleep
v[0]->join();  // <- instead, join
*v[0]=thread(f3);


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.
@Disch
reuse a thread is related with re-assign new function with it;
if I am right;
then how can I do it in my program?
if I am right;


You're not.

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.
thx
I need time to re thinking on it.
You don't need to store pointers to the threads, you can store them directly:
http://coliru.stacked-crooked.com/a/784112ce915efb33
Topic archived. No new replies allowed.