why boost thread executes immediately?

Nov 15, 2010 at 1:24pm
void f() {}

boost::thread thrd(&f);
the f() executes immediately after thrd is defined,

but what I need is something like this:
1
2
3
4
Thread t(&f); // just initialize but not execute
t.start();
t.stop();
t.start();


how can I use boost to do that?

and why boost doesn't split the initializing and executing?

Thanks in advance.
Last edited on Nov 15, 2010 at 1:26pm
Nov 15, 2010 at 2:52pm
Given that boost::thread does not have a run() or start() method, I'd say you can't directly do what you want.

Why do you want to split construction from thread creation? Can't you just delay construction of the thread
to the point at which you want to run it?
Nov 15, 2010 at 6:06pm
Perhaps try to wrap it up in your class, if you want to save your callable function and start it later.
Nov 15, 2010 at 8:53pm
He probably wants to start n threads and store them in an array/vector.
What I do is
1
2
3
4
5
6
7
std::vector<boost::thread *> threads(n);
for (size_t a=0;a<threads.size();a++)
    threads[a]=new boost::thread(f);
for (size_t a=0;a<threads.size();a++){
    threads[a]->join();
    delete threads[a];
}
std::auto_ptr is a possibility, too.
Nov 16, 2010 at 4:21am
oyeah, seems use a thread* pointer can solve this, I wrote a wrapper:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <boost/thread.hpp>

#include <iostream>
using namespace std;

template <typename T>
class Thread {
private:
	boost::thread* thread;
public:
	virtual void run() = 0;
	void start() {
		if(thread && thread->isRunning()) {// how to check if the thread is running?
			return;
		}
		thread = new boost::thread(&T::run, (T*)this);
	}
	//void kill() {
	//}
};


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "../Thread.h"

// usage:
// a concrete class for test
class test : public Thread<test> {
public:
	void run() {
		cout << "run" << endl;
	}
};

int main() {
    test t;
    t.start();

	return 0;
}

but how to check if a thread has finished or not? I can't find function like isRunning() or hasFinished() from boost::thread.

and another question is: if a thread function is block and takes long, such as:
for(i=0; i<veryLargeNumber; i++) {
// something block and takes very long time
}
how can I stop the thread? thread->interrupt() could kill that?
Nov 16, 2010 at 6:21am
if(thread && thread->isRunning()) {// how to check if the thread is running?
The typical solution is to allow only one call to start() per instance of Thread by setting a member.

how can I stop the thread? thread->interrupt() could kill that?
It's never a good idea to kill threads. Whenever possible and necessary, have the thread poll a flag and give all blocking I/O operations a timeout.

The Thread class can be implemented without templates, by the way. If you're going to have pure virtual functions, at least take advantage of polymorphism.
Nov 16, 2010 at 8:42am
closed account (S6k9GNh0)
There is a thread container made by boost called thread_group which is probably a bit more useful than std::vector (or at least, I use it anyways. I think its just preference.).

Besides that, I'm confused as to what you want to do? If the main objective is just to split the initialization and execution apart, I don't see the point.
Nov 16, 2010 at 4:19pm
yeah, I improved my wrapper class:
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
#include <boost/thread.hpp>

#include <iostream>
using namespace std;

class Thread {
private:
	boost::thread* thread;
	bool isRunning;
public:
	// Ctor
	Thread() : thread(NULL), isRunning(false) {
	}
	virtual ~Thread() {
		kill();
	}

public:
	virtual void operator()() = 0;

	void start() {
		if(!isFinished()) {
			return;
		}
		kill();
		thread = new boost::thread(boost::ref(*this)); // both of these two line causes  runtime exception
		//thread = new boost::thread(&Thread::doIt, boost::ref(*this));
	}
	void doIt() {
		try {
			isRunning = true;
    		(*this)();
			isRunning = false;
		} catch(boost::thread_interrupted&) {
			isRunning = false;
		}
	}
	bool isFinished() {
		return isRunning;
	}
	void join() {
		if(thread) {
			thread->join();
		}
	}
	void kill() {
		if(thread) {
			thread->interrupt();
			delete thread;
			thread = NULL;
		}
	}
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "../Thread.h"


class test : public Thread {
public:
	virtual void operator ()() {
		while(true) {
    		cout << "run" << endl;
    		boost::this_thread::interruption_point();
			boost::this_thread::sleep(boost::posix_time::millisec(500));
		}
	}
};

int main() {
    test t;
    t.start();

	return 0;
}

haha, it looks better now? I think the Thread class should support start/stop/isRunning/restart , but when I run the test, there is an exception. it seems the "this" pointer is wrong, how to let the "this" point to the derived class?
I'm new to boost, Thanks in advance.
Nov 16, 2010 at 4:57pm
There is no intrinsic way in the language; you have to design that part.

One option is to make your Thread wrapper a template class using CRTP.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template< typename Derived >
class Thread {

    public:
        void start() {
            if( !isFinished() ) return;
            Derived* pObj = dynamic_cast<Derived*>( this );
            assert( pObj );  // Should never fail...
            kill();
            thread = new boost::thread( boost::ref( *pObj ) );
       }
};

class test : public Thread< test > {
    // ...
};

Nov 16, 2010 at 5:33pm
Hi jsmith, this can solve it. but I feel a little uncomfortable to use both template and virtual function in this class :)
since the template is necessary here, is there anyway smart way to convert the "virtual operator()" to a template way?
Thanks.
Nov 16, 2010 at 7:02pm
The Thread base class no longer needs a pure virtual operator(). (It doesn't need it at all.)
Nov 17, 2010 at 5:13am
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
#include <boost/thread.hpp>

#pragma warning(disable: 4244)


#include <iostream>
using namespace std;

template<typename T>
class Thread {
......
public:

	void start() {
		T* derived = dynamic_cast<T*>(this);
		//thread = new boost::thread(boost::ref(*derived));
		thread = new boost::thread(boost::bind(&T::doIt, derived)); // why this line doesn't compile
		//thread = new boost::thread(boost::bind(&Thread::doIt, derived));// 
	}
	void doIt(T& obj) {
		try {
			isRunning = true;
    		obj();
			isRunning = false;
		} catch(boost::thread_interrupted&) {
			isRunning = false;
		}
	}
};

the two commented lines causes error on compile, I see some tutorial does exactly like this,
boost::thread( boost::bind(&menberFunc, objectReference) )
how can I fix this?
Nov 17, 2010 at 6:25am
You want

 
thread = new boost::thread( boost::bind( &Thread::doIt, this, boost::ref( *derived ) ) );



Nov 17, 2010 at 7:35am
jsmith (4946) Nov 17, 2010 at 2:25pm
You want


thread = new boost::thread( boost::bind( &Thread::doIt, this, boost::ref( *derived ) ) );


Thank you jsmith~
Nov 17, 2010 at 9:35am
the code compiles but I don't know why... see the comments below

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
template<typename T>
class Thread {
public:
	void start() {
		T* derived = dynamic_cast<T*>(this);
// there are 3 arguments in the boost::bind,
// argument 1(&thread::doIt)   and  argument 2(this)   means binding a member function
// but what's the 3th argument for? doesn't it mean the argument of doIt?
// I removed it and it also compiles
		thread = new boost::thread(boost::bind(&Thread::doIt, this, boost::ref(*derived)));
	}
//	void doIt() { // this compiles
		//(*derived)();
//	}
// this won't compile,  why doesn't  the third argument above used here
	void doIt(T* derived) {
		//(*derived)();
	}
};


Last edited on Nov 17, 2010 at 9:36am
Nov 18, 2010 at 1:56am
The line I gave you says to call Thread::doIt on the "this" object with boost::ref( *derived )
as the first parameter to doIt(). boost::ref() is a container that holds a non-const reference,
which is what your original doIt() expected.

In your code below, doIt takes a T*, which is a pointer, not a reference, hence the compile
error. If you want it to take a pointer for some reason, then change boost::ref( *derived )
to just derived.
Nov 18, 2010 at 5:07am
I tried both
1
2
3
4
5
6
7
8
9
10
template<typename T>
class Thread {
public:
	void start() {
		T* derived = dynamic_cast<T*>(this);
		thread = new boost::thread(boost::bind(&Thread::doIt, this, boost::ref(*derived)));
	}
	void doIt(T& derived) {
	}
};

and
1
2
3
4
5
6
7
8
9
10
template<typename T>
class Thread {
public:
	void start() {
		T* derived = dynamic_cast<T*>(this);
		thread = new boost::thread(boost::bind(&Thread::doIt, this, derived));
	}
	void doIt(T* derived) {
	}
};


but neither of them can compile, the compile error are the same:
error C2660: 'Thread<T>::doIt' : function does not take 0 arguments
Nov 18, 2010 at 1:28pm
Oh, it's my mistake, I called doIt() directly in main()....
Thank you again :)
Topic archived. No new replies allowed.