RE: [Boost-Users] Boost.Threads question
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.
Understood.
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).
Understood.
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
I assume you mean boost::timed_mutex::scoped_timed_lock lock(mutex,xt) because I don't see a constructor that takes only a timed_mutex. That said, I agree that your way of doing it is better. Above you asked why I continue to use the syntax I do for locking the mutex in the thread. I want to immediately lock it, then in the main thread try to lock it for a finite amount of time. I can't do that with scoped_lock. Perhaps my strategy is wrong. I want to run a thread for only a specified amount of time. I can't afford to block on a join() to wait for that thread to finish.
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.
Understood. Apologies for not thoroughly reading the doc first.
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.
What the application does is run a job (thread) that has a finite amount of time to finish. If it doesn't finish in that time it needs to send an alert and explicitly terminate the thread (because it can't be blocked with a join() unless it knows the thread is done). As stated above, perhaps my strategy of using the mutex to see if a thread ran in a given amount of time is wrong. Hopefully I'm making some sense, if not, I apologies. James
William E. Kempf
Info: http://www.boost.org Wiki: http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl Unsubscribe: mailto:boost-users-unsubscribe@yahoogroups.com Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
James Zappia said:
I assume you mean boost::timed_mutex::scoped_timed_lock lock(mutex,xt) because I don't see a constructor that takes only a timed_mutex.
Yep. Typo. Sorry.
That said, I agree that your way of doing it is better. Above you asked why I continue to use the syntax I do for locking the mutex in the thread. I want to immediately lock it, then in the main thread try to lock it for a finite amount of time. I can't do that with scoped_lock. Perhaps my strategy is wrong. I want to run a thread for only a specified amount of time. I can't afford to block on a join() to wait for that thread to finish.
I don't follow this. The test_thread can use a scoped_lock, while the main thread uses a scoped_timed_lock. There's no reason to use the scoped_timed_lock constructor which forces a non-timed lock in test_thread. As for not being able to wait on a join... why not? What do you expect to happen if you don't join?
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.
What the application does is run a job (thread) that has a finite amount of time to finish. If it doesn't finish in that time it needs to send an alert and explicitly terminate the thread (because it can't be blocked with a join() unless it knows the thread is done). As stated above, perhaps my strategy of using the mutex to see if a thread ran in a given amount of time is wrong.
First, it would probably be better to use a condition to wait for an "I'm finished" predicate, if for no other reason than it makes what you're trying to do clearer. Second, arbitrarily killing a thread is nearly always a bad idea, as it can leave the programs invariants in a broken state. The cancellation mechanism that will be added to Boost.Threads uses a cooperative model for this reason. Even with out cancellation support, this should be trivial to implement for your specific case. Third, I can't understand why you'd want to do what you're doing here. Either what the thread does is something that the main thread doesn't have to rely on, so there's no reason to wait at all, or it is something that you have to rely on and MUST wait for the thread to complete (as in call join()) even if you want said thread to complete within a given time frame. Maybe you need to drop the toy example and explain precisely what you want to accomplish here so that I can give better advice. William E. Kempf
participants (2)
-
James Zappia
-
William E. Kempf