COCKOS
CONFEDERATED FORUMS
Cockos : REAPER : NINJAM : Forums
Forum Home : Register : FAQ : Members List : Search :
Old 02-24-2010, 03:48 AM   #1
Soundbytes
Human being with feelings
 
Soundbytes's Avatar
 
Join Date: May 2006
Posts: 58
Default How can I start a new thread?

Hi all,

I am currently porting all my stuff to the IPlug framework.
Everything worked out remarkably well so far but now I am afraid I am stuck with a multithreading problem.
My Synth uses a multisample that is loaded from disk on user request.

The data is a couple of megabytes in size and I need to have a separate thread for the sample loader to avoid audio dropouts while the data is read.

Question: Is there a recommended way to create/start/stop a thread in WDL that works fine on all supported OS platforms?

I tried to find out how the plugin grapics thread is created but could not figure it out so far. Any hints are most welcome. Thanks!

Andreas
Soundbytes is offline   Reply With Quote
Old 02-24-2010, 05:16 AM   #2
cc_
Human being with feelings
 
Join Date: Mar 2009
Posts: 256
Default

I haven't used it yet, but swell has code in there for emulating the windows thread stuff on OSX using pthreads. Take a look in swell/swell.c there's CreateThread() etc.

So you should be able to write windows code and have it run on OSX too.

I'd be very interested in hearing how you get on...
cc_ is offline   Reply With Quote
Old 02-24-2010, 07:39 AM   #3
Soundbytes
Human being with feelings
 
Soundbytes's Avatar
 
Join Date: May 2006
Posts: 58
Default

Thanks! That looks exactly like what I was looking for (+ it answers a couple of questions that I was about to ask)
Soundbytes is offline   Reply With Quote
Old 02-25-2010, 01:33 AM   #4
junioreq
Human being with feelings
 
junioreq's Avatar
 
Join Date: Aug 2008
Location: Buffalo NY
Posts: 1,091
Default



..
Sorry, It was eating me up all day, I had to

~Rob.
junioreq is offline   Reply With Quote
Old 02-25-2010, 09:17 AM   #5
Soundbytes
Human being with feelings
 
Soundbytes's Avatar
 
Join Date: May 2006
Posts: 58
Default a thread class

Here is a first version of my threading class. It works fine in windows but unfortunately does not compile in OS X. It uses the GetExitCodeThread() WIN32 API function that is not supported by swell. Is there an alternative way to check the thread status that can be implemented with IPlug/swell?
I need to know the thread status because otherwise the thread object might be destroyed before the tread is properly exited.
Any hints are most welcome. Thanks!

The sb_thread class encapsulates all the complicated stuff and makes thread management available through simple start() and end functions().

Usage is quite straightforward - All You have to do is inhertit from that class and implent the doStuff() member function that runs within the daughter thread.
Note that the thread function does not have to be a global function or a static member function. This is all sorted out by the thread object.

This implementation is lock free. Instead it uses atomic shared variables to send commands and to signal the state of the thread.

have fun

Andreas

As an example here is dummy sample loader that uses the sb_thread object.
I would recommend to add the sample loader (or your customized thread object) as a member object to the plugin class.

start() can be called in Plugin::Resume(). (do not bloat the Plugin constructor by calling loader.start() there.)
There is no need to explicitly end the daughter thread. This is taken care of by the Plugin destructor.

Code:
//-- sb_dummySampleLoader declaration------------------------------

class sb_dummySampleLoader : public sb_thread // inherit!
{
public:
    sb_dummySampleLoader() : sampleIdx(0), sampleLoadDone(false) {isVirtual = false;}
    ~sb_dummySampleLoader(){isVirtual = true;}
    // This function is called by the main thread to trigger a
    // sample swap in the loader thread.
    void setNewSampleIdx( int newSampleIdx );

    // thread function - must be implemented.
    void doStuff();

    // all variables used by both threads need to be declared volatile 
    // _and_ they must be atomic (only then the communication can be lock free.)
    volatile bool sampleLoadDone;    
    volatile int  sampleIdx;        
};

//-- sb_dummySampleLoader implementation --------------------------

void setNewSampleIdx( int newSampleIdx )
{
    if( sampleIdx != newSampleIdx ){
        sampleIdx = newSampleIdx;
        // Signal to the loader thread that there is some work to do.
        sampleLoadDone = false; 
        // TODO: mute the audio process - access to the 
        // sample table is not possible now.
    }
}

void sb_dummySampleLoader::doStuff()
{
    while(true){
        // do stuff
        if (!sampleLoadDone){
            //
            // Load new sample[sampleIdx]
            //
            MessageBox( 
                NULL, 
                "New Sample Now Loading.\n(err, not quite yet.)", 
                "IPlug Example Synth", 
                0);
            sampleLoadDone = true; // was set false by the request.
        }
        Sleep(200);
        if(switchOff) break;
    }
}
Here is the sb_thread function that does the magic:
Code:
//-- sbThread declaration ----------------------------------------

class sb_thread
{
public:
    sb_thread() : hnd(NULL), switchOff(true), isVirtual(true) {}
    ~sb_thread(){
        end();
    }
    void start();
    void end();

protected:
    volatile bool isVirtual;
    volatile bool switchOff;
    virtual void doStuff() = 0;
private:
    static DWORD WINAPI threadProc( LPVOID pItem_ );
    HANDLE hnd;
    DWORD exitCode;
};

//-- sb_thread implementation ----------------------------------

void sb_thread::start(){ 
    // create the new thread only once
    if (hnd == 0){
        // reset state variables
        exitCode = 0;
        switchOff = false;

        hnd = CreateThread( NULL, 0, threadProc, this, 0, NULL);
    }
}

void sb_thread::end(){
    switchOff = true;
    // wait until thread is finished! 
    // This is crucial since otherwise it is not guaranteed that 
    // all objects created by the daughter thread are destroyed. 
    // (that is when end() is called from ~sb_thread().)
    if (hnd != 0){
        WaitForSingleObject(hnd ,INFINITE);
        CloseHandle(hnd);
        hnd = 0;
    }
}

DWORD WINAPI sb_thread::threadProc( LPVOID pThis_ ){
    sb_thread* pThis = (sb_thread*)pThis_;
    if(!pThis->isVirtual) pThis->doStuff();
    return 1;
}

Last edited by Soundbytes; 03-11-2010 at 03:25 PM. Reason: fixed an issue with cubase le 3 - enhanced cross platform compatibility
Soundbytes is offline   Reply With Quote
Old 02-25-2010, 09:54 AM   #6
Tale
Human being with feelings
 
Tale's Avatar
 
Join Date: Jul 2008
Location: The Netherlands
Posts: 2,938
Default

Quote:
Originally Posted by Soundbytes View Post
Here is a first version of my threading class. It works fine in windows but unfortunately does not compile in OS X. It uses the GetExitCodeThread() WIN32 API function that is not supported by swell. Is there an alternative way to check the thread status that can be implemented with IPlug/swell?
I need to know the thread status because otherwise the thread object might be destroyed before the tread is properly exited.
Any hints are most welcome. Thanks!
I don't know much about threads, but I think WaitForSingleObject(hdn, 0) does what you want.
Tale is online now   Reply With Quote
Old 02-25-2010, 10:09 AM   #7
Jeffos
Mortal
 
Jeffos's Avatar
 
Join Date: Dec 2008
Location: France
Posts: 1,969
Default

yes, this is what I do in order to stop a thread properly (here "m_quit" breaks a threading loop):
Code:
    if (m_thread)
    {
      m_quit=true;
      WaitForSingleObject(m_thread,INFINITE);
      CloseHandle(m_thread);
      m_thread=0;
    }
both WaitForSingleObject and CloseHandle seems mapped in swell.h but I can't tell much more about OSX..

[edit] "INFINITE" = 0xFFFFFFFF !

Last edited by Jeffos; 02-25-2010 at 10:19 AM. Reason: 0xFFFFFFFF
Jeffos is offline   Reply With Quote
Old 02-25-2010, 12:55 PM   #8
Soundbytes
Human being with feelings
 
Soundbytes's Avatar
 
Join Date: May 2006
Posts: 58
Default How to make the IPlug project swell aware?

I am stuck again. I implemented the proposed changes and still the plugin does not compile as OS X AU. In fact it seems that the definitions and defines from swell.h are not recognized all together.
Initially I had thought that swell.h was already included with the Xcode project. Then I included swell.h explicitly within myPlugin.h with no success either. Finally I copied the main.h from the swell demo project and included that. Still none of the swell wrapped functions and data types is recognized. what am I doing wrong? Thanks!

Andreas
Soundbytes is offline   Reply With Quote
Old 02-25-2010, 02:43 PM   #9
cc_
Human being with feelings
 
Join Date: Mar 2009
Posts: 256
Default

You will need to include swell.h in the files that use the emulated functions at least.

What are the errors you are getting exactly?
cc_ is offline   Reply With Quote
Old 02-26-2010, 05:07 AM   #10
Soundbytes
Human being with feelings
 
Soundbytes's Avatar
 
Join Date: May 2006
Posts: 58
Default

Quote:
Originally Posted by cc_ View Post
You will need to include swell.h in the files that use the emulated functions at least.

What are the errors you are getting exactly?
I thought they were compiler errors however on looking closer I found that I got linker errors. The fix was easy then. I just had to include the missing source files with the Xcode project. :-)
Soundbytes is offline   Reply With Quote
Old 02-26-2010, 08:25 AM   #11
cc_
Human being with feelings
 
Join Date: Mar 2009
Posts: 256
Default

I thought it might be that, but then I thought that stuff was compiled with IPlug, what files did you have to add?
cc_ is offline   Reply With Quote
Old 02-27-2010, 05:58 AM   #12
Soundbytes
Human being with feelings
 
Soundbytes's Avatar
 
Join Date: May 2006
Posts: 58
Default

Quote:
Originally Posted by cc_ View Post
I thought it might be that, but then I thought that stuff was compiled with IPlug, what files did you have to add?
I checked the IPlug Xcode project.
It includes these swell files (in group Lice > Swell):

swell-gdi.mm
swell-misc.mm
swell-internal.h
swell.h

To make my Plugin compile I added these files to my project:

swell.cpp
swell-kb.mm
swell-menu.mm
swell-misc.mm
swell-miscdlg.mm
swell-wnd.mm
swell-appstub.mm
swell-dlg.mm
swell-gdi.mm
swell-ini.mm

I admit I did not do much research. Instead I just copied the list from the swell example app and removed those files that gave me compiler errors. I chose the files just by trial and error and did not look deeper in what's in there. At the moment I am just happy that my plugin compiles and that I did not have to spend much more time looking into the details of the swell library. (will do that later)

Andreas



Andreas
Soundbytes is offline   Reply With Quote
Old 03-11-2010, 03:18 PM   #13
Soundbytes
Human being with feelings
 
Soundbytes's Avatar
 
Join Date: May 2006
Posts: 58
Default Bugfix

Hi,
I found that Cubase LE 3 did not really like my code. (it worked fine with Cubase 5 and with all other hosts that I have tried so far)

When the plugin is loaded for the first time Cubase 3 tries to do some tests. It creates a plugin instance then calls setSampleRate() (which in turn triggers an IPLug Reset() )
This is where my thread process is started. The Plugin object is now destroyed and unfortunately my thread function is then executed right after the underlying object has gone away. Bang!

I have now fixed the issue. The thread class example a few posts above contains the updated code.

Andreas
__________________
www.soundbytes.de
Soundbytes is offline   Reply With Quote
Old 01-23-2017, 01:44 PM   #14
leighhunt
Human being with feelings
 
Join Date: Jun 2016
Location: London, UK
Posts: 35
Default

Hi there Andreas and all concerned in this thread.
Well, it took me two evenings to accomplish, but now I am the happy user of a separate thread in a plugin I am building.
I can only begin to thank you all for your explanations, albeit from some time ago!

Kind regards,
Leigh
leighhunt is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 01:37 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2019, vBulletin Solutions Inc.