How to enqueue TQueue from TTask with bcc32

by Oct 3, 2017

When considering migration from old C++Builder 10.2 Tokyo bcc32 project.
You can use functions such as TThread::CreateAnonymousThread() and TTask to improve performance.
In addition to TCriticalSection, you can also use System.TMonitor which supports multiple devices.
I will show you how to program bcc32 project using the above method.

TQueue<String> is created in Delphi.

TQueue<T> is in System::Generics::Collections.
To use TQueue<String>, describe it in Delphi as follows.

uses
  System.Generics.Collections;
type
  TQueStr = class(TQueue<String>)
  end

You can now use TQueue__1<System::UnicodeString>.

Create a class to run in the interior of the TTask.

//_proc is a struct to execute TTask::start().
struct _proc: TCppInterfacedObject<TProc>
{
    TQueue__1<System::UnicodeString>* f_queue_;
    TObject* f_mutex_;      //TObject behaves like a mutex.
    int f_number;

    _proc(int i, TObject* lmtx, TQueue__1<System::UnicodeString>* lq):TCppInterfacedObject<TProc>(){
        f_mutex_ = lmtx;
        f_queue_ = lq;
        f_number = i;       //This is the number where the Task is executed.
    }

    //Convert from int to string.
    std::string int_to_string(const int i)
    {
        std::ostringstream ss;
        ss << i;
        return ss.str();
    }

    //Executed in TTask.
    void __fastcall Invoke(){
        std::string s = "TTask" + int_to_string(f_number+1//Lock with TMonitor.
        System::TMonitor::Enter(f_mutex_);
        try
        {
            //Add a character to the common TQueue<String>.
            f_queue_->Enqueue(s.c_str());
            //Sleep(100);
        }
        __finally
        {
            //UnLock with TMonitor.
            System::TMonitor::Exit(f_mutex_);
        }
    }
    inline __fastcall virtual ~_proc(void){
    }
};

Actually executed is void __fastcall Invoke(){}.
The internal in the task memory each other will use the System::TMonitor::Enter(f_mutex_); so as not to conflict.

It is a class that creates many TTasks.

We have created and stored many TTasks in std::vector<_di_ITask>.

struct _queue_task
{
    TQueue__1<System::UnicodeString>* f_queue;
    TObject* f_mutex;           //TObject behaves like a mutex.
    std::vector<_di_ITask> v1;  //_di_ITask is managed with std::vector.
    _queue_task(){
        f_queue = new TQueue__1<System::UnicodeString>();
        f_mutex = new TObject();
    }
    std::vector<_di_ITask>& start(const int icount)
    {
        // Only the number of purpose, to create a TTask.
        for (int li = 0//The TTask is _proc::Invoke() is executed.
            v1.push_back(TTask::Create(_di_TProc( new _proc(li, f_mutex, f_queue))));
        }
        for (std::vector<_di_ITask>::iterator tsk = v1.begin(); tsk != v1.end(); ++tsk)
        {
            //Start the TTask in the std::vector in order.
            (*tsk)->Start();
        }
        return v1;
    }
    virtual ~_queue_task()
    {
        //Destructor
        delete f_queue;
        delete f_mutex;
    }
};

Using TThread::CreateAnonymousThread() etc., the design method as shown below is also possible.