How to pass CriticalSection (compilation error with JUCE_DELETED_FUNCTION)?


#1

I have seen CriticalSection/ScopedLock not working issue, and there it is mentioned:

It looks like what I questioned earlier. Your
code shows each thread having it’s own critical section which will do
nothing. The threads need to act on the same CriticalSection instance.

e.g. (something to this effect)

CriticalSection cs;  //the single critical section used by all the threads
CSTrial cst1 (cs);  //pass the critical section to cst1
CSTrial cst2 (cs);  //pass the same critical section to cst2

Ok, so I tried to implement this: I created a new GUI application in Projucer, and then used the following code:

MainComponent.h

/* 
  ============================================================================== 
 
    This file was auto-generated! 
 
  ============================================================================== 
*/ 
 
#ifndef MAINCOMPONENT_H_INCLUDED 
#define MAINCOMPONENT_H_INCLUDED 
 
#include "../JuceLibraryCode/JuceHeader.h" 
 
 
//============================================================================== 
/* 
    This component lives inside our window, and this is where you should put all 
    your controls and content. 
*/ 
class MainContentComponent   : public Component 
{ 
public: 
    //============================================================================== 
    MainContentComponent(); 
    ~MainContentComponent(); 
 
    void paint (Graphics&) override; 
    void resized() override; 
 
    CriticalSection maincs; 
 
private: 
    //============================================================================== 
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent) 
}; 
 
 
#endif  // MAINCOMPONENT_H_INCLUDED 

MainComponent.cpp

#include "MainComponent.h" 
 
// if you comment this define, compilation succeeds: 
#define PASSCS 
 
static int counter = 0; 
class CSTrial : public Thread 
{ 
public: 
    #ifndef PASSCS 
    CSTrial(): Thread("CS Trial " + String(++counter)) //OK 
    #else 
    CSTrial(CriticalSection incs):  Thread("CS Trial " + String(++counter)), 
                                    cs(incs) 
    #endif 
    { 
        id = counter; 
        startThread(1); 
    } 
    ~CSTrial() 
    { 
        signalThreadShouldExit(); 
        waitForThreadToExit(-1); 
    } 
    //@override 
    void run() 
    { 
        const ScopedLock sl(cs); 
        doStuff(); 
        sleep(500); 
        std::cerr << id << ": about to end run()\n"; 
    } 
    void doStuff() 
    { 
        std::cerr << id << ": do Stuff\n"; 
    } 
    CriticalSection cs; 
    int id; 
}; 
 
//============================================================================== 
MainContentComponent::MainContentComponent() 
{ 
    setSize (600, 400); 
    #ifndef PASSCS 
    CSTrial cst1; //ok 
    CSTrial cst2; //ok 
    #else 
    CSTrial cst1(maincs); 
    CSTrial cst2(maincs); 
    #endif 
} 
 
MainContentComponent::~MainContentComponent() 
{ 
} 
 
void MainContentComponent::paint (Graphics& g) 
{ 
    g.fillAll (Colour (0xff001F36)); 
 
    g.setFont (Font (16.0f)); 
    g.setColour (Colours::white); 
    g.drawText ("Hello World!", getLocalBounds(), Justification::centred, true); 
} 
 
void MainContentComponent::resized() 
{ 
    // This is called when the MainContentComponent is resized. 
    // If you add any child components, this is where you should 
    // update their positions. 
} 

So, here if the PASSCS is not defined (#define PASSCS is commented), then everything compiles, however, the critical section locking doesn’t work, as in the original posting.

If PASSCS is defined (#define PASSCS is not commented), then I cannot compile, getting this compilation error:

Compiling MainComponent.cpp 
In file included from ../../../../modules/juce_core/system/juce_StandardHeader.h:65:0, 
                 from ../../../../modules/juce_core/juce_core.h:182, 
                 from ../../../../modules/juce_audio_basics/juce_audio_basics.h:60, 
                 from ../../Source/../JuceLibraryCode/JuceHeader.h:18, 
                 from ../../Source/MainComponent.h:12, 
                 from ../../Source/MainComponent.cpp:9: 
../../../../modules/juce_core/threads/juce_CriticalSection.h: In constructor ‘CSTrial::CSTrial(juce::CriticalSection)’: 
../../../../modules/juce_core/threads/juce_CriticalSection.h:124:32: error: ‘juce::CriticalSection::CriticalSection(const juce::CriticalSection&)’ is private 
     JUCE_DECLARE_NON_COPYABLE (CriticalSection) 
                                ^ 
../../../../modules/juce_core/system/juce_PlatformDefs.h:224:5: note: in definition of macro ‘JUCE_DECLARE_NON_COPYABLE’ 
     className (const className&) JUCE_DELETED_FUNCTION;\ 
     ^ 
../../Source/MainComponent.cpp:22:44: error: within this context 
                                     cs(incs) 
                                            ^ 
../../Source/MainComponent.cpp:22:44: error: use of deleted function ‘juce::CriticalSection::CriticalSection(const juce::CriticalSection&)’ 
In file included from ../../../../modules/juce_core/system/juce_StandardHeader.h:65:0, 
                 from ../../../../modules/juce_core/juce_core.h:182, 
                 from ../../../../modules/juce_audio_basics/juce_audio_basics.h:60, 
                 from ../../Source/../JuceLibraryCode/JuceHeader.h:18, 
                 from ../../Source/MainComponent.h:12, 
                 from ../../Source/MainComponent.cpp:9: 
../../../../modules/juce_core/threads/juce_CriticalSection.h:124:32: error: declared here 
     JUCE_DECLARE_NON_COPYABLE (CriticalSection) 
                                ^ 
../../../../modules/juce_core/system/juce_PlatformDefs.h:224:5: note: in definition of macro ‘JUCE_DECLARE_NON_COPYABLE’ 
     className (const className&) JUCE_DELETED_FUNCTION;\ 
     ^ 
../../../../modules/juce_core/threads/juce_CriticalSection.h: In constructor ‘MainContentComponent::MainContentComponent()’: 
../../../../modules/juce_core/threads/juce_CriticalSection.h:124:32: error: ‘juce::CriticalSection::CriticalSection(const juce::CriticalSection&)’ is private 
     JUCE_DECLARE_NON_COPYABLE (CriticalSection) 
                                ^ 
../../../../modules/juce_core/system/juce_PlatformDefs.h:224:5: note: in definition of macro ‘JUCE_DECLARE_NON_COPYABLE’ 
     className (const className&) JUCE_DELETED_FUNCTION;\ 
     ^ 
../../Source/MainComponent.cpp:57:24: error: within this context 
     CSTrial cst1(maincs); 
                        ^ 
../../Source/MainComponent.cpp:57:24: error: use of deleted function ‘juce::CriticalSection::CriticalSection(const juce::CriticalSection&)’ 
In file included from ../../../../modules/juce_core/system/juce_StandardHeader.h:65:0, 
                 from ../../../../modules/juce_core/juce_core.h:182, 
                 from ../../../../modules/juce_audio_basics/juce_audio_basics.h:60, 
                 from ../../Source/../JuceLibraryCode/JuceHeader.h:18, 
                 from ../../Source/MainComponent.h:12, 
                 from ../../Source/MainComponent.cpp:9: 
../../../../modules/juce_core/threads/juce_CriticalSection.h:124:32: error: declared here 
     JUCE_DECLARE_NON_COPYABLE (CriticalSection) 
                                ^ 
../../../../modules/juce_core/system/juce_PlatformDefs.h:224:5: note: in definition of macro ‘JUCE_DECLARE_NON_COPYABLE’ 
     className (const className&) JUCE_DELETED_FUNCTION;\ 
     ^ 
../../Source/MainComponent.cpp:21:5: error:   initializing argument 1 of ‘CSTrial::CSTrial(juce::CriticalSection)’ 
     CSTrial(CriticalSection incs):  Thread("CS Trial " + String(++counter)), 
     ^ 
In file included from ../../../../modules/juce_core/system/juce_StandardHeader.h:65:0, 
                 from ../../../../modules/juce_core/juce_core.h:182, 
                 from ../../../../modules/juce_audio_basics/juce_audio_basics.h:60, 
                 from ../../Source/../JuceLibraryCode/JuceHeader.h:18, 
                 from ../../Source/MainComponent.h:12, 
                 from ../../Source/MainComponent.cpp:9: 
../../../../modules/juce_core/threads/juce_CriticalSection.h:124:32: error: ‘juce::CriticalSection::CriticalSection(const juce::CriticalSection&)’ is private 
     JUCE_DECLARE_NON_COPYABLE (CriticalSection) 
                                ^ 
../../../../modules/juce_core/system/juce_PlatformDefs.h:224:5: note: in definition of macro ‘JUCE_DECLARE_NON_COPYABLE’ 
     className (const className&) JUCE_DELETED_FUNCTION;\ 
     ^ 
../../Source/MainComponent.cpp:58:24: error: within this context 
     CSTrial cst2(maincs); 
                        ^ 
../../Source/MainComponent.cpp:58:24: error: use of deleted function ‘juce::CriticalSection::CriticalSection(const juce::CriticalSection&)’ 
In file included from ../../../../modules/juce_core/system/juce_StandardHeader.h:65:0, 
                 from ../../../../modules/juce_core/juce_core.h:182, 
                 from ../../../../modules/juce_audio_basics/juce_audio_basics.h:60, 
                 from ../../Source/../JuceLibraryCode/JuceHeader.h:18, 
                 from ../../Source/MainComponent.h:12, 
                 from ../../Source/MainComponent.cpp:9: 
../../../../modules/juce_core/threads/juce_CriticalSection.h:124:32: error: declared here 
     JUCE_DECLARE_NON_COPYABLE (CriticalSection) 
                                ^ 
../../../../modules/juce_core/system/juce_PlatformDefs.h:224:5: note: in definition of macro ‘JUCE_DECLARE_NON_COPYABLE’ 
     className (const className&) JUCE_DELETED_FUNCTION;\ 
     ^ 
../../Source/MainComponent.cpp:21:5: error:   initializing argument 1 of ‘CSTrial::CSTrial(juce::CriticalSection)’ 
     CSTrial(CriticalSection incs):  Thread("CS Trial " + String(++counter)), 
     ^ 
make: *** [build/intermediate/Debug/MainComponent_a6ffb4a5.o] Error 1 

This is on Linux (Ubuntu 14.04).

So, apparently I cannot pass a CriticalSection, as noted in the original post? Or can I, and I simply don’t know how to do it? In my case, I’d want to synchronize code parts that reside in two different components, which is why I’d need to create one CriticalSection on MainComponent level, and then pass it to the “child” classes that need the code synchronized. How do I do that?

Unfortunately, it seems there is no example for this “passing” anywhere in ./examples or ./extras, which is why I need to ask this question in the first place - if I have missed the example, kindly point me to it…


#2

Your code tries to copy the criticalSection, because in your CSTrial class you declare a new instance of CriticalSection and in the constructor you assign the original one to the instance of the class. For the compiler this is copying the instance, but that is explicitly disabled by JUCE_DECLARE_NON_COPYABLE (CriticalSection).

This has a good reason, because if you copy it, you end up with the scenario you wanted to avoid in the first place. You want them to act on the same critical section.

You can resolve that by setting it as reference.
In your CSTrial class change the argument to pass a reference:

CSTrial(CriticalSection& incs):  Thread("CS Trial " + String(++counter)), 
                                 cs(incs)

And define cs as reference as well:

CriticalSection& cs;

N.B. it is your responsibility to make sure, the original CriticalSection is avalilable during the lifetime of all CSTrial instances, otherwise you get crashes at runtime…


#3

Many thanks for the answer, @daniel ! Now that you’ve explained it, it makes a lot of sense that I should have used a reference instead - shame I couldn’t figure it out myself :slight_smile:

Thanks again!