Home > Back-end >  How to share data between a TThread in a DLL and the main thread?
How to share data between a TThread in a DLL and the main thread?

Time:04-08

I'm writing a DLL in C Builder XE6, that creates a separate thread (derived from TThread) to retrieve JSON data from a REST server every X seconds (using TIdHTTP), and parse the JSON data.

The thread fills a simple struct (no dynamically allocated data) with the parsed JSON data in the Execute() method of the thread:

typedef struct
{
    char MyString[40   1];
    double MyDouble;
    bool MyBool;
} TMyStruct;

The thread should store the struct in a list, for example a std::vector:

#include <vector>

std::vector<TMyStruct> MyList;

The thread will add a TMyStruct to the list:

TMyStruct Data;
...
MyList.push_back(Data);

The list will be guarded by a TCriticalSection to prevent data corruption.

The DLL exports a function to retrieve a TMyStruct from MyList.

bool __declspec(dllexport) __stdcall GetMyStruct (int Index, TMyStruct* Data)
{
    ...
}

Only thing is, I don't know where to put MyList...

If I make MyList a global variable, it is located in the main thread's memory and GetMyStruct() can access it directly. How does the thread access MyList?

If I make MyList a member of the TThread-derived class, it is located in the thread's memory and the thread can access it directly. How does GetMyStruct() access MyList?

What is the best/prefered/common way to store MyList and access it in a different thread?

CodePudding user response:

If I make MyList a global variable, it is located in the main thread's memory and GetMyStruct() can access it directly. How does the thread access MyList?

The exact same way. All threads in a process can freely access global variables within that process. For example:

#include <vector>
#include <System.SyncObjs.hpp>

typedef struct
{
    char MyString[40   1];
    double MyDouble;
    bool MyBool;
} TMyStruct;

std::vector<TMyStruct> MyList;
TCriticalSection *Lock = NULL; // why not std::mutex instead?

class TMyThread : public TThread
{
    ...
};
TMyThread *Thread = NULL;

...

void __fastcall TMyThread::Execute()
{
    TMyStruct Data;
    ...
    Lock->Enter();
    try {
        MyList.push_back(Data);
    }
    __finally {
        Lock->Leave();
    }
    ...
}

...

void __declspec(dllexport) __stdcall StartThread ()
{
    Lock = new TCriticalSection;
    Thread = new TMyThread;
}

void __declspec(dllexport) __stdcall StopThread ()
{
    if (Thread) {
        Thread->Terminate();
        Thread->WaitFor();
        delete Thread;
        Thread = NULL;
    }
    if (Lock) {
        delete Lock;
        Lock = NULL;
    }
}

bool __declspec(dllexport) __stdcall GetMyStruct (int Index, TMyStruct* Data)
{
    if (!(Lock && Thread)) return false;

    Lock->Enter();
    try {
        *Data = MyList[Index];
    }
    __finally {
        Lock->Leave();
    }

    return true;
}

If I make MyList a member of the TThread-derived class, it is located in the thread's memory and the thread can access it directly. How does GetMyStruct() access MyList?

By accessing it via a pointer to the thread object. For example:

#include <vector>
#include <System.SyncObjs.hpp>

typedef struct
{
    char MyString[40   1];
    double MyDouble;
    bool MyBool;
} TMyStruct;

class TMyThread : public TThread
{
protected:
    void __fastcall Execute();
public:
    __fastcall TMyThread();
    __fastcall ~TMyThread();

    std::vector<TMyStruct> MyList;
    TCriticalSection *Lock;
};

TMyThread *Thread = NULL;

...

__fastcall TMyThread::TMyThread()
    : TThread(false)
{
    Lock = new TCriticalSection;
}

__fastcall TMyThread::~TMyThread()
{
    delete Lock;
}

void __fastcall TMyThread::Execute()
{
    TMyStruct Data;
    ...
    Lock->Enter();
    try {
        MyList.push_back(Data);
    }
    __finally {
        Lock->Leave();
    }
    ...
}

void __declspec(dllexport) __stdcall StartThread ()
{
    Thread = new TMyThread;
}

void __declspec(dllexport) __stdcall StopThread ()
{
    if (Thread) {
        Thread->Terminate();
        Thread->WaitFor();
        delete Thread;
        Thread = NULL;
    }
}

bool __declspec(dllexport) __stdcall GetMyStruct (int Index, TMyStruct* Data)
{
    if (!Thread) return false;

    Thread->Lock->Enter();
    try {
        *Data = Thread->MyList[Index];
    }
    __finally {
        Thread->Lock->Leave();
    }

    return true;
}

What is the best/prefered/common way to store MyList and access it in a different thread?

That is entirely up to you to decide, based on your particular needs and project design.

  • Related