Boost logo

Boost Users :

From: William E. Kempf (wekempf_at_[hidden])
Date: 2002-12-05 11:06:42


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 <boost/thread/xtime.hpp>
> #include <boost/thread/thread.hpp>
> #include <boost/thread/exceptions.hpp>
>
> 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


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net