James Zappia said:
Thank you, that worked. I see what I was doing wrong.
One thing I don't understand about the alternative method...
boost::try_mutex::scoped_try_lock lock(mutex); // does a try_lock while (!lock) { cout << "trying..."; lock.try_lock(); }
How does "!lock" in the "while (!lock) { ... }" statement determine whether it's true or false? Does it call a function in the scoped_try_lock class? (sorry if that's a lame question...)
Hmmm... this doesn't seem to be documented very well. I'll have to fix that. What it does is invoke operator void*() for a boolean test (this mechanism also should be updated to use the safe_bool idiom as well). Alternatively, you could call lock.locked() (which also appears to be poorly documented). Thanks for pointing out these deficiencies.
William E. Kempf
Thanks for all you help. I have a few new questions now, though. ;) Again, I'm a newbie to C++ so this may seem stupid...
I created a boost::thread object and even though it goes out of scope, the thread continues to run.
As it should, and as it's well documented. The boost::thread object is analogous to a std::fstream, where the file doesn't get deleted when the object goes out of scope. In other words, it's just a handle to the actual running thread.
Also, when passing a class with the operator() defined to boost::thread, it constructs and destructs the object several times which seems odd.
Also well documented, and essential. If this didn't occur, you'd have to insure the lifetime of the object passed was longer than the lifetime of the thread of execution (not the boost::thread object, the actual thread of execution).
What I'm basically trying to do is run a thread, have that thread lock a timed_mutex, then do its job. Then, in main, I try to lock the same timed_mutex and if I can't get a lock before the time expires, I need to terminate the thread. Below is the source code and the output generated. My questions are below, after the output.
SOURCE: #include <iostream> #include
#include #include using namespace std;
boost::timed_mutex mutex;
class thread_class { public: explicit thread_class(int sleep): _sleep(sleep) {};
void operator()() { boost::xtime xt;
cout << "thread: locking mutex\n"; boost::timed_mutex::scoped_timed_lock lock(mutex,true);
Why do you continue to use this syntax? This performs an explicit lock, not a timed lock. This overload is for two use cases: 1) Creating an unlocked lock object: scoped_time_lock lock(mutex, false); 2) Creating a locked lock object which later will be unlocked and then locked again through a timed lock: scoped_time_lock lock(mutex, true); // .. some code lock.unlock(); // .. some code if (lock.timed_lock()) { // .. some code } Obviously the second use case will be extremely rare. In your case you're doing neither of these, and you'd be better served just using a simple scoped_lock.
boost::xtime_get(&xt,boost::TIME_UTC);
cout << "thread: sleeping for " << _sleep << " seconds\n";
xt.sec += _sleep; boost::thread::sleep(xt);
cout << "thread: freeing lock -- goodbye\n"; }
~thread_class() { cout << "thread_class destructed\n"; }
private: int _sleep; };
int main( void ) { { cout << "main: creating thread\n";
thread_class test(10); boost::thread thrd(test);
cout << "main: sleeping for 2 seconds\n"; sleep(2);
cout << "main: trying to lock mutex -- waiting 5 seconds...\n";
boost::timed_mutex::scoped_timed_lock lock(mutex,false);
boost::xtime xt; boost::xtime_get(&xt,boost::TIME_UTC); xt.sec += 5;
if ( lock.timed_lock(xt) ) { cout << "obtain lock -- joining thread\n"; thrd.join(); } else { cout << "failed to obtain lock\n"; } }
I'd code this as: boost::xtime xt; boost::xtime_get(&xt, boost::TIME_UTC); xt.sec += 5; boost::timed_mutex::scoped_time_lock lock(mutex); if (lock) // or if (lock.locked()) { // etc
cout << "main: making sure thread is gone\n";
That's what join is for. I realize this is a toy example, but I can't see a valid reason for coding it this way. All you've done is introduce race conditions, even if they are conditions you can feel fairly confident will do what you want.
sleep(10);
return 0; }
OUTPUT: main: creating thread thread_class destructed thread_class destructed thread_class destructed thread_class destructed main: sleeping for 2 seconds thread: locking mutex thread: sleeping for 10 seconds main: trying to lock mutex -- waiting 5 seconds... failed to obtain lock thread_class destructed main: making sure thread is gone thread: freeing lock -- goodbye thread_class destructed
1) Why are so many thread_class objects constructed/destructed when calling boost::thread?
The number surprises me a little. I'd have expected two copies, knowing what I do about the implementation and with out carefully evaluating the code here. But the documentation is clear that the object will be copied AT LEAST once, and is free to copy the object any number of times. You need to account for this in your implementation if it matters.
2) After the thread object (test) goes out of scope, why does the thread continue to run? Is it copied when calling boost::thread and run detached from the main thread?
I don't know what you mean by "run detached from the main thread", but yes, test IS copied (but then, you know that based on what you asked in 1). But then, maybe you meant something else. The "thread object" is actually "thrd" in your code above, not "test".
3) Is there a way I can cancel a thread if going out of scope doesn't stop it?
Not yet, but there will be. However, I'm not sure that what you want to do is really to cancel the thread. It's hard to tell from this toy example. William E. Kempf