How can I create a thread in my MainComponent?

gui

#1

I created a MainComponent which contains a textEditor and a sceneComponent. Now I want to keep reading data from a MASTERPROOF Digital percentile meter and printing the data in the textEditor. Besides I want to draw lines in the sceneComponent according to the data.
So, I plan to create a thread to keep reading data while the main thread can draw lines according to the data. But it went worng when I created the thread in the MainComponent.
I would appreciate it if someone can tell me how to create and use the thread.


#2

In multi threading, it doesn’t matter so much, where you create it. You can create it in your main(), in your MainComponent, you can even create it in AudioProcessor.

BUT it matters, which thread calls which function.

To create a thread, you inherit from Thread and override the run() method. So far nothing happened, there is still only one thread running. What you do is, when you call startThread(), the OS is running the run() method, and this is now parallel and completely without effecting all other code. Once the run() method finishes, the thread is stopped.

Your problem starts now, how to get the data, that you read to the MainComponent, so that the paint() can draw it.

A variable must not be accessed from two threads in parallel. One approach is, wrapping the variable into an atomic. This wrapper makes sure, that reading and writing doesn’t occur in parallel (otherwise, you end up with undefined behaviour, imagine a float is stored in 4 bytes, if one byte is updated, but the other one isn’t, and you cannot know which one).

Untested example:

class MainComponent : public Component, private Timer
{
public:
    MainComponent()
    {
        meterThread.startThread();
        startTimerHz (30);
    }

    ~MainComponent()
    {
        meterThread.stopThread();
    }

    void paint (Graphics& g)
    {
        auto value = meterThread.value.load();
        g.drawFittedText (String value, getLocalBounds(), Justification::centred, 1);
    }

    void timerCallback()
    {
        repaint();
    }
private:
    class MeterThread : private Thread
    {
    public:
        MeterThread() : Thread ("Meter thread") {}

        void run() override
        {
            while (! threadShouldExit())
            {
                // read from your meter
                value.store (readFromMeter());

                sleep (10); // avoid burning CPU, if reading is returning immediately
            }
        }
        std::atomic<float> value { 0.0f };
    };

    MeterThread meterThread;
}

Other methods to pass data between threads, is a circular buffer, or a lock-free queue. Depending on the kind of information you want to pass along, you can choose between the different ones.


#3

Does JUCE have circular buffers and lock-free queues?


#4

JUCE has the AbstractFIFO class which is a good choice for some kind of queues.


#5

Amazing! Not sure how I missed that before!


#6

@daniel: In your example, you use sleep() instead of wait(). Is there a particular advantage to one over the other?


#7

Yes, a significant one. Calling wait() stops the thread, until somewhere someone (i.e. a different thread) calls notify(). But no one knows, when to notify the thread, so I used sleep(), which just pauses the thread execution for 10 msecs and continues running. In this time other threads have the chance to use that processor core.

If you have the chance to get a notify(), that is the preferred version, since you can avoid running the thread in vain.


#8

Good to know! Thanks!


#9

wait() also has a timeout parameter, so if needed, you can wake up for both a notify or a timeout. And you can differentiate by the return value from wait(), true if it’s been signaled, or false if it’s timed out.


#10

Good shout, yes. Thanks for the addition!


#11

Thank you so much, I will try it in my code.


#12

Does tthere has a function which can add values to the end or begin of the textEditor in juce? I had looked up the function of the textEditor, but not found the proper one.


#13

I think you are looking for TextEditor::insertTextAtCaret()


#14

Yes, I had looked the details of this function, but not understand what’s mean of:“at the current caret position”
Does it means I can insert values directly while the former texts won’t be replaced?


#15

It behaves like a normal text editor with a caret you can move through the text. Usually it will be left at the end, if you didn’t set it somewhere else with setCaretPosition (int position), or if it is set editable, the user can click the caret to a position of his choice.


#16

Ok, I get it.
Thank you very much for your explanation and kindly advice :blush: