Threading and wait/notify


#1

I have a component, inheriting Thread. I do searching task in a separated thread, for example:

void ProductsComponent::run() { Manager m; String name = m.findFile(); // takes much time const MessageManagerLock mml(Thread::getCurrentThread()); anylabel->setText(name, false); }

How and where should I properly suspend/resume this 2nd thread (possibly with wait/notify) ?
Thanks


#2

This is exacty what vf::ThreadWithCallQueue is for.

Given

vf::ThreadWithCallQueue t;

And this method:

void ProductsComponent::findFileAsync () { Manager m; String name = m.findFile(); // takes much time vf::MessageThread::getInstance().call (&Label::setText, anyLabel, name, false); }

From a separate thread where c is a pointer to ProductsComponent we can issue

t.call (&ProductsComponent::findFileAsync, c);

Note that we don’t have to lock the message thread anymore, this uses vf::MessageThread instead.


#3

Btw, I took some time to look at the concurrency classes of VFLib this weekend,
and there is some really nice stuff in there, TheVinn.

If it only were better documented I bet people would use it more and know about it.


#4

[quote=“TheVinn”]This is exacty what vf::ThreadWithCallQueue is for.

Given

vf::ThreadWithCallQueue t;

And this method:

void ProductsComponent::findFileAsync () { Manager m; String name = m.findFile(); // takes much time vf::MessageThread::getInstance().call (&Label::setText, anyLabel, name, false); }

From a separate thread where c is a pointer to ProductsComponent we can issue

t.call (&ProductsComponent::findFileAsync, c);

Note that we don’t have to lock the message thread anymore, this uses vf::MessageThread instead.[/quote]
Hi! Thanks fir this.I’ll look at it since it is interesting to me, but my question is not about locking messages.

Ok, just to clarify my problem. My real task is - when I push a button, a component starts installation (unpacking, moving multiple files etc.) in the separated thread inside

void ProductsComponent::run() { }

If I push another button to stop intallation, then a messagebox is shown with text “Are you really want to stop installation”. It means that during the time when messagebox is shown I should suspend my installation thread. If I push “Yes” it stops the thread, if “No” - resumes the one. First of all I’d like to know if it is possible to do with standard juce? If no I’ll probably go with vflib


#5

VFLib uses JUCE.

So, you want to force the thread to suspend itself? JUCE threads don’t do that. If you want your thread to be interruptible then you need to periodically check to see if an interruption was requested, and write your code in a way that it does its work in small chunks. It’s not safe to just kill an operating system thread. Again, VFLib to the rescue.

Use vf::InterruptibleThread to allow your thread to be interrupted. Note that vf::ThreadWithCallQueue is also interruptible, just put your work into the idle function. For both styles of thread, call InterruptibleThread::interruptionPoint from inside your thread procedure to check to see if an interruption was requested. From outside the thread call InterruptibleThread::interrupt to signal that the thread should be interrupted.


#6

[quote=“TheVinn”]
So, you want to force the thread to suspend itself?[/quote]
Not itself, but from main (GUI) thread.

VFLib seems to be useful for that. Is there any demo of using one?


#7

[quote=“acid”][quote=“TheVinn”]
So, you want to force the thread to suspend itself?[/quote]
Not itself, but from main (GUI) thread.

VFLib seems to be useful for that. Is there any demo of using one?[/quote]

There is no way that I know if in either VFLib or JUCE to “suspend” a thread. Operating systems usually provide this function but it is dangerous to use, because you don’t know at what place in the code the thread is currently executing.

If you want to make a thread that can be interrupted you need to write your thread function so that it periodically checks a flag (this is how VFLib does it). To “suspend” the thread, check the flag to abort the current operation and then call the wait function on a synchronization primitive. JUCE threads have a built in event object which you can signal and wait on using Thread::wait and Thread::notify.


#8

Btw, on the implementation of threads…

Since with C++11 threads became an official part of the standard library, and the std::thread implementation is really
nice and powerful beyond what’s currently available in Juce, I think it would be worthwhile to at least think about providing
a Juce Thread implementation built on std::thread, for those compiler targets that already support it (gcc 4, vc10 & vc11, clang). At a later point in time, when old compilers fall off the cliff sooner or later, the native implementations based on pthread and Win32 threads can silently go away then.

That would be especially handy since the new standard library brings along very nice stuff like promises and futures, asynchronous execution of functors, thread return values, and of course the ability to implement thread bodies as functors/ lambda functions.


#9

[quote=“lucem”]Btw, on the implementation of threads…

Since with C++11 threads became an official part of the standard library, and the std::thread implementation is really
nice and powerful beyond what’s currently available in Juce, I think it would be worthwhile to at least think about providing
a Juce Thread implementation built on std::thread, for those compiler targets that already support it (gcc 4, vc10 & vc11, clang). At a later point in time, when old compilers fall off the cliff sooner or later, the native implementations based on pthread and Win32 threads can silently go away then.

That would be especially handy since the new standard library brings along very nice stuff like promises and futures, asynchronous execution of functors, thread return values, and of course the ability to implement thread bodies as functors/ lambda functions.[/quote]

Yes, indeed, I’m very much looking forward to moving on to all the nice new stuff. If you’re using C++11 you can of course already use all those classes, but sadly it’ll be a few years before juce can drop compatibility with all the old MSVC versions :frowning:


#10

Sure, i know that dropping compiler support for vc9 and before is not an option per se
(although I do think that at least vc6 could be dropped now due to age and standard library issues).

What I’d really like is a refactoring of the existing thread implementation into a pure virtual interface and concrete
implementations based on native / portable / standard library threading libraries, with configuration switches to select
which actual implementation is used (factory pattern, anyone?).
I’m not too sure about using std::thread in combination with the existing juce::thread implementation, and I doubt that it
would be painless or clean to mix them, so an implementation based on std::thread would very much help out in that regard.
As a fallback for compilers that don’t support std::thread already, there is always the possible fallback to native threads or boost::thread.


#11

By the way, i know you’re pretty busy, so don’t feel pushed into making this happen.

I’d love to look into that myself, and maybe if I get around (workQueueItemCollection.size != empty) to play with it
I can come up with an implementation based on std::thread myself, we’ll see.
I guess if I do and give it to you, chances of it actually being merged were rising :wink:


#12

Yep, posting some code to start from does vastly increase the chances of getting me to do something!


#13

[quote=“lucem”]What I’d really like is a refactoring of the existing thread implementation into a pure virtual interface and concrete
implementations based on native / portable / standard library threading libraries, with configuration switches to select
which actual implementation is used (factory pattern, anyone?).
I’m not too sure about using std::thread in combination with the existing juce::thread implementation, and I doubt that it
would be painless or clean to mix them, so an implementation based on std::thread would very much help out in that regard.
As a fallback for compilers that don’t support std::thread already, there is always the possible fallback to native threads or boost::thread.[/quote]

Why is any of this needed? JUCE threads work great now and they already have a cross platform interface. If you want to use std::thread, nothing is stopping you (except that your code might not compile on older IDEs). What will having a JUCE::Thread that uses std::thread let you do that you cannot do currently?


#14

As I said, I’d want to use the functionality of the std::thread implementation and everything that comes with it alongside the Juce implementation, and I’m not convinced that mixing that would play out nicely.

Addition to clarify:
As the Juce Audio and Midi systems already use Juce Threads, I cannot for my use case switch to only standard library threads without breaking Juce (which I wouldn’t want to do, maintaining a personal fork is a PITA).
However, I especially need promises and futures, which are rather hard to create by foot, and most certainly would not meet the quality of testing, robustness and performance as the standard library implementation (which is basically the old boost::thread).
Thus, having an optional (read: brought in by setting a flag at compile time) implementation of Juce threads on top of std::thread, with exposure to sth std::thread interface shall it be used and so desired, would very much be beneficial.


C++ threads vs JUCE threads - threading tutorials?
#15

Why not? They will both use the same operating system primitive…


#16

I've just tried using std::thread with a non-JUCE WinRT application, since it's much closer to a 'standard' thread API (Windows or Posix) than WinRT's asynchronous task nonsense.

 

Not really impressed:

 

-  It's impossible to set the thread's stack size (for secondary threads on mobile apps I can usually reduce this right down)

- On Win32, every call to std::mutex allocates/deallocates heap memory via the standard new operator.  Since I believe this is meant to be a constexpr, I don't even think this implementation is 'legal'.  Certainly it plays havok with my leak detecting debug memory manager, which needs to lock a mutex during allocations, which causes an allocation, which causes a lock, which causes an allocation ... etc.

 

The std::thread API is simple, which is good until you need to do something a bit special (eg. set thread priority).  On some platforms this can instead be achieved by getting the native handle from std::thread and doing it the old fashioned way.

In short, I don't think std::thread's ready for prime time in performance critical/real time applications and I'm not if it'll ever be.  I make this judgement based on statements like, "you can't set a stack size for std::threads because some platforms don't have a stack'.  It's never going to be an optimal implementation if they want to keep the API abstracted this far from real world hardware.

Also, it's unclear if std::mutex (or the more useful std::recursive_mutex) is using the lighter weight CriticalSection or the heavyweight Mutex on Windows.