waiting for another thread without blocking resources...

L

Lars Uffmann

In an event routine, I want to end a certain thread. I am setting a flag
that is checked by the thread and causes it to end, when it is set. Then
the thread sets a "response" flag, just before exiting. In the event
routine, I would like to wait for that response flag, because at that
point, I can be sure that the old thread (even if it still is alive
between setting the response flag and exiting) will no longer interfere
with a subsequent call.

However, a

while (!responseflag);

heavily blocks system resources and apparently also the read call blocks
the writing of the responseflag - I get caught in an endless loop there.

while (!responseflag) cout << "." << endl;

seems to do the job, with a random amount of periods printed to stdout,
but I wouldn't rely on it always working. So what is the thing to do
within that while loop?

TIA!

Lars
 
T

Thomas J. Gritzan

Lars said:
In an event routine, I want to end a certain thread. I am setting a flag
that is checked by the thread and causes it to end, when it is set. Then
the thread sets a "response" flag, just before exiting. In the event
routine, I would like to wait for that response flag, because at that
point, I can be sure that the old thread (even if it still is alive
between setting the response flag and exiting) will no longer interfere
with a subsequent call.

However, a

while (!responseflag);

heavily blocks system resources and apparently also the read call blocks
the writing of the responseflag - I get caught in an endless loop there.

If you want to wait in a thread, you should not use a loop, but simply
wait. There might be some functions like WaitForSomeCondition() in your
threading library, and you should ask this question in a newsgroup about
your platform or threading library.
 
S

Szabolcs Ferenczi

while (!responseflag);

heavily blocks system resources and ...

It can improve you situation a little bit, if you release the
processor while waiting, e.g.:

while (!responseflag) sched_yield();

Of course, the actual instruction for yielding depends on what library
you are using.

However, you might consider using a semaphore for event signaling.

Best Regards,
Szabolcs
 
L

Lars Uffmann

Thomas said:
If you want to wait in a thread, you should not use a loop, but simply
wait. There might be some functions like WaitForSomeCondition() in your
threading library, and you should ask this question in a newsgroup about
your platform or threading library.

boost only has a mailing list :/
And the thing is, actually my event procedure is not a thread. I was
hoping there was some way to have a button that starts and ends a thread:

First Click:
-> set keepalive flag, start thread, thread set's a "i'm running" flag,
then checks keepalive flag every cycle

Second Click:
-> unset keepalive flag, wait for "i'm running" flag to be un-set,
thread ends upon next check, unsets "i'm running"

For that I only have 1 thread, and the event procedure cannot be a
thread, nor should it be. There's got to be some c++ sleep function that
gives the thread some time to terminate, without blocking resources...

Or isn't there?

*confused*

Lars
 
L

Lars Uffmann

Szabolcs said:
It can improve you situation a little bit, if you release the
processor while waiting, e.g.:
while (!responseflag) sched_yield();

Given I find such a function, wouldn't I have to sched_yield for a given
amount of time? Otherwise the stack operations for the bazillion
sched_yield calls would eat up system resources en masse...

Best Regards,

Lars
 
C

Cholo Lennon

Given I find such a function, wouldn't I have to sched_yield for a given
amount of time? Otherwise the stack operations for the bazillion
sched_yield calls would eat up system resources en masse...

Best Regards,

Lars

If you are using boost, just call 'join':


// Signal for termination
your_thread.SetTerminationFlag();

// Wait for termination
your_thread.join();

// Here, your thread is terminated
....

Regards
 
L

Lars Uffmann

Cholo said:
If you are using boost, just call 'join':

Thank you, now I got the problem that join() never returns, instead my
application crashes - AFTER the last line of code in the thread of
execution, and before the line following the join statement in the
calling event procedure... Someone doesn't like me here.

What's worse, the news portal to the boost mailing list causes my
thunderbird to create a severe error message upon attempting to post...

Does anyone happen to have a link to a good boost documentatin?
http://boost.org/libs/libraries.htm doesn't quite cut it...

Thank you!

Lars
 
C

Cholo Lennon

Thank you, now I got the problem that join() never returns, instead my
application crashes - AFTER the last line of code in the thread of
execution, and before the line following the join statement in the
calling event procedure... Someone doesn't like me here.

AFAIK 2 possibilities:

1- Your thread signaling is not working (it seems that it's not your
situation, but...).

2- Your thread is not 'joinable'. Threads are joinable if they are
built with a ctor functor parameter (you will get an assert calling
'join' on a non-joinable thread)


What's worse, the news portal to the boost mailing list causes my
thunderbird to create a severe error message upon attempting to post...

Does anyone happen to have a link to a good boost documentatin?http://boost.org/libs/libraries.htmdoesn't quite cut it...

The boost thread documentation is not the best (lacks of basic
examples). Try looking the source code examples provided by the
library (looking the underlaying implementation is a good idea too;
It's straightforward if you know win threads or pthreads)

Regards
 
Y

Yannick Tremblay

Thank you, now I got the problem that join() never returns, instead my
application crashes - AFTER the last line of code in the thread of
execution, and before the line following the join statement in the
calling event procedure... Someone doesn't like me here.

What's worse, the news portal to the boost mailing list causes my
thunderbird to create a severe error message upon attempting to post...

Does anyone happen to have a link to a good boost documentatin?
http://boost.org/libs/libraries.htm doesn't quite cut it...

Well, boost is kind of on-topic here so:

IMO, boost should be seen as a collection of libraries, not as one
monolithic lib. Some of these libraries have better documentation
than others. For boost::thread, IMO,
http://www.boost.org/doc/html/thread.html is perfectly adequate
documentation.

You are probably interested in:

boost::condition
boost::condition::wait

Download the boost archive and go through the tutorial in
../boost/libs/thread/tutorial/

and the examples in:
../boost/libs/thread/example/

The bounded_buffer.cpp and monitor.cpp examples should be of interest
to you. In your type of application you probably want independent GUI
thread and service thread that communicate exclusively using a shared
EventQueue that is mutex protected. In the pop/receive/read method of
your EventQueue, you lock the mutex, check if there is some Event on
the queue, if yes, de-queue and return that event, if not call a
condition.wait. The push/send/write method is responsible to signal
the condition if it adds an event to a previously empty queue.

class EventQueue
{

private:
boost::mutex m_mutex;
boost::condition m_condition;
// an actual containers e.g. std::queue
}

Event EventQeueue::receive()
{
boost::ScopedLock L(m_mutex);
if( /* the container is empty (e.g. m_queue.empty() )
{
m_condition.wait(L);
}
Event ev = /* get an Event from the container */
return ev;
}

in the send(Event const &) method, uses condition::notify_all() or
condition::notify_one() to signal possibly waiting threads if the
container has become non-empty (e.g. size == 1). You may also want to
use while(/*container empty*/) rather than if()

The above can be written generic using templates as a container
adaptor (or inheritance). E.g.
class TreadSafeContainer< std::queue< Event > > EventQueue;

I think boost discussion are OK here. If you want to talk more
spacifically about multithreading issues themselves
comp.programming.threads might be a forum of interest to you.

Yan
 
L

Lars Uffmann

Cholo said:
AFAIK 2 possibilities:
[...]
2- Your thread is not 'joinable'. Threads are joinable if they are
built with a ctor functor parameter (you will get an assert calling
'join' on a non-joinable thread)

Yes, I do construct it with a function parameter, I was told this is the
only way to construct a thread? In the meantime I've also seen the
reset-function, so I am very confused now... So how do I make a joinable
thread? Construct it with thread:thread() and then call thread::reset
(functor parameter)?
The boost thread documentation is not the best (lacks of basic
examples). Try looking the source code examples provided by the
library (looking the underlaying implementation is a good idea too;
It's straightforward if you know win threads or pthreads)

Well - I don't know either... Guess I'll have to get a hardcopy of some
book...

Best Regards & Thanks for your help so far...


Lars
 
L

Lars Uffmann

Hi Yannick,

Thank you very much for your extensive reply - that seems to be shedding
some light on threading for me, but since I'll need some time to do what
you suggested, I wanted to post a quick reply first :)

Best Regards,

Lars
 
C

Cholo Lennon

Cholo said:
AFAIK 2 possibilities:
[...]
2- Your thread is not 'joinable'. Threads are joinable if they are
built with a ctor functor parameter (you will get an assert calling
'join' on a non-joinable thread)

Yes, I do construct it with a function parameter, I was told this is the
only way to construct a thread? In the meantime I've also seen the
reset-function, so I am very confused now... So how do I make a joinable
thread? Construct it with thread:thread() and then call thread::reset
(functor parameter)?
The boost thread documentation is not the best (lacks of basic
examples). Try looking the source code examples provided by the
library (looking the underlaying implementation is a good idea too;
It's straightforward if you know win threads or pthreads)

Well - I don't know either... Guess I'll have to get a hardcopy of some
book...

Best Regards & Thanks for your help so far...

Lars

Take a look to thread's ctors:

Code:
thread::thread()
    : m_joinable(false)
{
#if defined(BOOST_HAS_WINTHREADS)
    m_thread = reinterpret_cast<void*>(GetCurrentThread());
    m_id = GetCurrentThreadId();
#elif ...
  ...
}

// explicit ctor
thread::thread(const function0<void>& threadfunc)
    : m_joinable(true)
{
    thread_param param(threadfunc);
#if defined(BOOST_HAS_WINTHREADS)
    m_thread = reinterpret_cast<void*>(
      _beginthreadex(
        0, 0, &thread_proxy, &param, 0, &m_id));

    if (!m_thread)
        throw thread_resource_error();
#elif..
 ...
#endif
    param.wait();
}

If you provide a functor, you are constructing a 'joinable' thread.
Ctor without parameter constructs a thread that take the ownership of
the calling thread (this is useful in some situations).

Another way is (as Yannick told you) to use a condition (synchronized
flag). You must wait for a 'set' condition (the 'exit' thread
condition). On the ground, condition::wait calls the same function
than thread::join to perform the wait operation.

Regards

PS: Could you provide some code to check the library use?
 
J

James Kanze

In an event routine, I want to end a certain thread. I am
setting a flag that is checked by the thread and causes it to
end, when it is set. Then the thread sets a "response" flag,
just before exiting. In the event routine, I would like to
wait for that response flag, because at that point, I can be
sure that the old thread (even if it still is alive between
setting the response flag and exiting) will no longer
interfere with a subsequent call.
However, a
while (!responseflag);
heavily blocks system resources and apparently also the read
call blocks the writing of the responseflag - I get caught in
an endless loop there.
while (!responseflag) cout << "." << endl;
seems to do the job, with a random amount of periods printed
to stdout, but I wouldn't rely on it always working. So what
is the thing to do within that while loop?

Not only does it use an ungodly amount of CPU time to do
nothing, it isn't guaranteed to work. You need some sort of
synchronization around the accesses to responseflag, since it is
being modified, and more than one thread is accessing it.

The standard solution here is to use a condition. Something
like:

bool responseflag ;
boost::mutex responseMutex ;
boost::condition responseCond ;

void
waitForResponse()
{
boost::mutex::scoped_lock l( &responseMutex ) ;
while ( ! responseflag ) {
responseCond.wait( l ) ;
}
}

And of course, to modify the flag, you'll need:

void
setResponse( bool newValue )
{
boost::mutex::scoped_lock l( &responseMutex ) ;
responseflag = newValue ;
responseCond.notify_all() ;
}

(And of course, this just calls to be put in a simple
synchronization class.)

However: if all you want to do is wait for the end of the
thread, what's wrong with join?
 
J

James Kanze

Thank you, now I got the problem that join() never returns,
instead my application crashes - AFTER the last line of code
in the thread of execution, and before the line following
the join statement in the calling event procedure... Someone
doesn't like me here.
[/QUOTE]
AFAIK 2 possibilities:
1- Your thread signaling is not working (it seems that it's not your
situation, but...).
2- Your thread is not 'joinable'. Threads are joinable if they
are built with a ctor functor parameter (you will get an
assert calling 'join' on a non-joinable thread)

More correctly: a "thread" is joinable as long as the
boost::thread object which started it has not been destructed,
and can only be joined on that particular object. Certainly not
the best design around, but usable if you're careful. If you
plan on joining, it's probably best to wrap the boost::thread in
a class of your own, which inhibits copy and assignment, and
asserts that join has been called in the destructor. (For a
detached thread, you just wrap it in a function, which creates
the boost::thread object on the stack, and returns once the
thread has started.)
The boost thread documentation is not the best (lacks of basic
examples).

The boost thread documentation presupposes that you understand
threading in general; it documents the interfaces provided by
boost, but not the theory of how to write and organize threaded
code in general.

For that, you'd need a book. (The Butenhof is a good starting
point.)
 
L

Lars Uffmann

Cholo said:
PS: Could you provide some code to check the library use?

boost::thread *THREAD_FileReceiver; // global variable
int GLB_listen = 0; // global
int GLB_listening = 0; // global

// event handler function
void OnToggleListen()
{
if (!GLB_listen) {
if (GLB_listening) {
cout << "error: still ending thread" << endl;
return;
}
GLB_listen = 1; // set keepalive flag for thread
cout << "starting thread" << endl;

// this function is the threads main loop, receiving UDP packets
THREAD_FileReceiver = new boost::thread(&listenForUDPFiles);

// wait for thread to set GLB_Listening := 1 - how??

// the following is the cmd button to toggle thread status
mainWindow->cmdToggleListen->SetLabel ("Stop Listening");
}
else {
if (!GLB_listening) {
cout << "error: still starting thread" << endl;
return;
}
GLB_listen = 0; // unset keepalive flag for thread

// send a UDP packet to get thread out of listening mode
sendEndOfStream();

cout << "waiting for thread to end" << endl;
THREAD_FileReceiver->join();
cout << "thread finished, GLB_listening = " << GLB_listening << endl;
delete THREAD_FileReceiver;
THREAD_FileReceiver = 0;

// the following is the cmd button to toggle thread status
mainWindow->cmdToggleListen->SetLabel ("Start Listening");
}
}

---
this code just crashes after the join() call while without it, the code
would exit normally. However, then I have a possible race condition when
re-activating the thread. Are you able to make anything from that?

Thanks,

Lars
 
L

Lars Uffmann

James said:
More correctly: a "thread" is joinable as long as the
boost::thread object which started it has not been destructed,
and can only be joined on that particular object.

Are you saying I can not join the thread with a calling function (event
handler)? That would render join pretty much useless, wouldn't it?

Is anyone working on a reference documentation for boost.thread btw? I'm
happy to provide inputs / feedback to that, for this iterative approach
getting to know the quirks of the library is just a nightmare, and all
your help is really appreciated!

Best Regards,

Lars
 
L

Lars Uffmann

James said:
However: if all you want to do is wait for the end of the
thread, what's wrong with join?

That it's crashing my application :/
I'll have a look into the condition things - but without more knowledge
about boost.thread, I cannot efficiently debug to locate my crash
problem (between last thread line of code and before returning from join()).

A kingdom for a boost reference documentation like
http://www.cplusplus.com/reference/


Best Regards,

Lars
 
J

James Kanze

Are you saying I can not join the thread with a calling
function (event handler)? That would render join pretty much
useless, wouldn't it?

I'm not sure what you mean. You can't join a thread if the
thread object which started it has been destructed. There's
certainly nothing that says you can't pass a pointer or a
reference to this object into a function, and do the join there.
Is anyone working on a reference documentation for
boost.thread btw? I'm happy to provide inputs / feedback to
that, for this iterative approach getting to know the quirks
of the library is just a nightmare, and all your help is
really appreciated!

I'm not sure what the problem is. Boost thread seems pretty
well documented to me. (I learned about this business about
joinable/detached threads from the documentation.)
 
C

Cholo Lennon

boost::thread *THREAD_FileReceiver; // global variable
int GLB_listen = 0; // global
int GLB_listening = 0; // global

// event handler function
void OnToggleListen()
{
if (!GLB_listen) {
if (GLB_listening) {
cout << "error: still ending thread" << endl;
return;
}
GLB_listen = 1; // set keepalive flag for thread
cout << "starting thread" << endl;

// this function is the threads main loop, receiving UDP packets
THREAD_FileReceiver = new boost::thread(&listenForUDPFiles);

// wait for thread to set GLB_Listening := 1 - how??

// the following is the cmd button to toggle thread status
mainWindow->cmdToggleListen->SetLabel ("Stop Listening");
}
else {
if (!GLB_listening) {
cout << "error: still starting thread" << endl;
return;
}
GLB_listen = 0; // unset keepalive flag for thread

// send a UDP packet to get thread out of listening mode
sendEndOfStream();

cout << "waiting for thread to end" << endl;
THREAD_FileReceiver->join();
cout << "thread finished, GLB_listening = " << GLB_listening << endl;
delete THREAD_FileReceiver;
THREAD_FileReceiver = 0;

// the following is the cmd button to toggle thread status
mainWindow->cmdToggleListen->SetLabel ("Start Listening");
}

}

Yes, it's possible that you have a race condition. Try locking the
section. Global variables aren't good, but using the same scheme:

....
boost::mutex GLB_mutex;

void OnToggleListen()
{
boost::scoped_lock(GLB_mutex);

// your code ...
}

Also, try locking global variable access in your thread function.

void listenForUDPFiles()
{
...

// Access shared flags (GLB_listen, GLB_listening)
{
boost::scoped_lock sl(GLB_mutex);

// update flags here
}
...
}

TODO: 1st Check if the solution work. 2nd Remove global variables and
optimize locking.


Regards
 
L

Lars Uffmann

Cholo said:
Yes, it's possible that you have a race condition. Try locking the
section. Global variables aren't good, but using the same scheme:

Hey Cholo, thank you for your advice. It turns out it was - once again -
my inexperience and sheer stupidity. I forgot I had started the thread
upon initialization of my application, and at THAT point (from an
earlier design) I was still deleting the boost::thread object right
after starting the thread of execution. AND setting it to 0. Now what
happens if you call ((boost::thread *) 0)->join() ... well... I don't
really need to comment on that, or do I?

Problem solved, nevertheless I'll have a loop into mutexes soon, hoping
I won't need them here.

Best Regards,

Lars
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top