0

In the last few weeks I've been very busy creating a custom inhouse code editor based on the fine TSynEdit component.

There's some background processing of the editor lines neede for validating the user input and highlighting potentially wrong syntax. This processing is triggered every 500 milliseconds by a TTimer on the main form.

The validator thread iterates over every line filling a

std::map<int, String>

with a line number / error text.

TSynEdit's OnSpecialLineColor event is looking for the corresponding line in the map and if IsEmpty() is false, the line's background becomes red.

To make the SynEdit sufficiently thread-safe without the need of using Synchronize() or some WinAPI message stuff, my idea was, to use some kind of code like this:

#include <memory>

#define BOOST_THREAD_USE_LIB
namespace boost { extern "C" void tss_cleanup_implemented(void) {}; }
#include <boost/thread.hpp>


class TMySynEdit : public TSynEdit
{
private:
    boost::mutex FMutexLines;

    TStrings* GetLines()
    {
        boost::lock_guard<boost::mutex> guard(FMutexLines);
        return TSynEdit::Lines;
    }

    void SetLines(TStrings* ALines)
    {
        boost::lock_guard<boost::mutex> guard(FMutexLines);
        TSynEdit::Lines = ALines;
    }

public:
    __fastcall TMySynEdit(TComponent* AOwner)
        :   TSynEdit(AOwner)
    {}

    virtual __fastcall ~TMySynEdit()
    {}

    __property TStrings* Lines = {read=GetLines, write=SetLines};
};

It overwrites the property Lines of TSynEdit with a thread-safe(?) one.

The timer-triggered thread is a parsing function running in a boost::thread.

My question now is: Is this an adequate solution, or am I missing something here?

FlKo
  • 805
  • 1
  • 10
  • 27
  • Your solution is not even remotely thread-safe, since you are only protecting the `Lines` property itself, but not any accesses to the individual lines within the `Lines` object. Where is your actual processing thread? `TTimer` is not a thread. Is your timer signaling another thread to do something? Why are you using a UI timer for that, instead of a sleep loop, or a waitable timer, in the thread itself? – Remy Lebeau Dec 22 '16 at 23:29
  • The actual code is on my working machine and I"m in my Xmas holidays now, so I can only give a brief explanation: – FlKo Dec 23 '16 at 06:52
  • The first idea was to not using threads at all here, 'cause of all the side effects. So the App had two individual timers on main form. One for the UI control enabling and one for the 'error processing, which took some small number of lines rack tick. That was pretty slow so I changed it as mentioned. The timer creates a thread for the parsing function like this: boost::thread thrd(&MyClass::ParsingFunc, this); – FlKo Dec 23 '16 at 07:06
  • The parsing function is just a for loop iterating over Lines creating a class based on the contents and checking values. If that class is signalled ng an error, this is being written into the error map. – FlKo Dec 23 '16 at 07:11
  • this sounds like a pretty wasteful use of threads. You are creating a new thread every 500ms, and it has to finish before 500ms elapses when the next thread is created. Threads are expensive to create and destroy. You may as well run the parser in the main UI thread in real time while the user is typing, and not worry about syncing access to the lines. – Remy Lebeau Dec 23 '16 at 10:25

1 Answers1

0

Thanks to Remy, I will probably return to the non-thread version when I'm back at work.

FlKo
  • 805
  • 1
  • 10
  • 27