Thread context on Delphi - multithreading

I am creating a server that starts a thread (listening thread). This thread listens for connections and does it's thing. Eventually it may receive some data, that I want to pass to the creator of the server:
My program --> Creates my server --> Creates the listener --> Creates a thread for every client
Now the question is: if I assign a property OnData = procedure (const Received: string) of object; to the server when I create it, and then, this same procedure is passed to the client threads, so when the thread get some data, it will be able to pass it back to the creator of the server. In pseudocode:
//My program
MyServer:= TServer.Create();
MyServer.Ondata:= SomeProcedure;
//The client thread
//When data is received
if (FServer <> nil) then
if Assigned(FServer.Ondata) then
Fserver.Ondata(ReceivedString)..
The questions here are:
1- I understand that if 10 threads execute this procedure at the same time, the procedure will be execute in the client thread context, so is the responsibility of my program (the actual "owner" of the procedure) to synchronize. Is that right?
2- If 10 different threads execute the procedure do I have 10 "instances" of the procedure with it's own data running at the same time?
3- Do I need to protect the OnData on the Server object as well (say, with a critical section), or it's OK to leave it to the "actual" procedure?

Yes. When the thread is running, all the code it runs gets executed within its own thread context, unless that code's been sent to another thread, for example with the Synchronize method.
Almost. You have 10 instances of the TThread object, each with its own data, running at the same time. There's only one copy of the actual code to the procedure, but multiple data objects can use it at once.
Any code that's not thread-safe (that might access the VCL, or that will write to any shared data, or read from shared data that something else might write to) needs to be protected.

Related

How to sync Delphi event while running DB operations in a background thread?

Using Delphi 7 & UIB, I'm running database operations in a background thread to eliminate problems like:
Timeout
Priority
Immediate Force-reconnect after network-loss
Non-blocked UI
Keeping an opened DB connection alive
User canceling
I've read ALL related topics here, and realized: using while isMyThreadStillRuning and not UserCanceled do sleep(100); end; isn't the recommended way to do this, but rather using TEvent.WaitFor(3000)....
The solutions here are either about sending signals FROM or TO... the thread, or doing it with messages, but never both ways.
Reading the help file, I've also found TSimpleEvent, which seems to be easier to use.
So what is the recommended way to communicate between Main-UI + DB-Thread in both ways?
Should I simply create 2+2 TSimpleEvent?
to start a new transaction (thread should stop sleeping)
force-STOP execution
to signal back if it's moved to a new stage (transaction started / executed / commited=done)
to signal back if there is any error happened
or should there be only 1 TEvent?
Update 2:
First tests show:
2x TSimpleEvent is enough (1 for Thread + 1 for Gui)
Both created as public properties of the background thread
Force-terminating the thread does not work. (Too many errors impossible to handle..)
Better to set a variable like (Stop_yourself) and let it cancel and free itself, (while creating a new instance from the same class and try again.)
(still work in progress...)
You should move the query to a TThread. Unfortunately, anonymous threads are not available in D7 so you need to write your own TThread derived class. Inside, you need its own DB connection to prevent shared resources. From the caller method, you can wait for the thread to end. The results should be stored somewhere in the caller class. Ensure that the access to parameters of the query and for storing the result of the query is handled thread-safe by using a TMutex or TMonitor.

Accessing the same object from concurrent threads

Have two object instance that i should access from two concurrent thread, from the VCL thread and from a worker thread.
TSlave = class
...
public
...
statusByte: byte;
...
end;
TMaster = class
private
FSlaves: TList;
FrBuffer: array of byte;
...
public
CMD_GET_SLAVE( aSlave: TSlave );
...
end;
procedure TMaster.CMD_GET_SLAVE( aSlave: TSlave );
begin
...
rBuffer := udpsend(); //calling a function that sends udp packet and returns the answer
aSlave.statusByte := rBuffer[2];
...
end;
I store the references of the slave objects in the 'Data' fields of VCL TTreeNodes - treenode.data (i store them also in a TMaster private list).
There are two 'option' for accessing the slave object (writing slave.statusByte) and the TMaster instance (as i access the slave object through a TMaster instance) >>
Clicking on the treenode. When this happens i send an UDP packet with calling master.CMD_GET_SLAVE, in this method i read the answer from FrBuffer and writing slave.statusByte.
There is a worker thread that is cyclically doing the same (calling master.CMD_GET_SLAVE). This case i dont get the slave instances from treenode.data, but from the master's TList object (FSlaves).
The question is, how to manage this correctly? Because there is a possible situation when the user clicks on the treenode and in the same time there could be an incoming access from the thread.
I dont touch any VCL control from the worker thread, 'just' accessing the same objects from two concurrent thread. Should i just do the same synchronization that im doing when synchronizing the main VCL thread (because of refreshing some visual VCL control)?
If you have multiple threads that access access a shared object, and at least one thread modifies the object, then you usually need to use a lock (for instance TCriticalSection or TMonitor) to serialize access to the shared object. Some options for doing so:
Externally protect all access to the shared object with the lock.
Make the object self synchronizing using its own private lock. That is the internally synchronized option.
Option 2 is simpler for the caller, but forces all consumers of the class to pay the cost of synchronization. A an alternative is to make the object have no internal synchronization but then wrap a synchronization class around it that presents a thread-safe version.
In this particular example, accessing the slaves across multiple threads is not a problem. The real problem is udpsend(). You are running the risk of having two threads sending requests at the same time and then reading each other's responses. Depending on the nature of your UDP protocol, that may or may not cause problems.
If it does, you might need to move the UDP communications to its own dedicated thread. When you need to send a request, you could put it in a thread-safe queue that the thread looks at, along with info about what to do with the response when it arrives (assign it to a slave, call a callback function, signal a waitable event, etc). The thread can pick up a queued request and send it. When the response comes back, it can delegate it accordingly. CMD_GET_SLAVE() would then block its calling thread waiting for that response to arrive. This would help avoid any overlaps.

Delphi tIdTCPClient with timer events and other multi-threaded client side events

We have a Delphi client server application using INDY. The client has a single tIdTCPClient connection to the server which is multi threaded. The client is "theoretically" a single thread. But in practice there are multiple threads on the client and this is where my problem is. For example think of a timer that fires every minute to get data from the server. And consider what happens when a user runs a command at the same time as this timer event. In truth, my problem is caused by our "Report Builder" reporting tool that (annoyingly) insists on loading every page of a report, which takes a while. The report runs off our "special" dataset that has a caching mechanism to transmit batches of records at a time (so multiple calls to the server to get all data). Meanwhile if a user does something else at the same time we seem to be getting crossed data. It seems the user getting back data that was meant for the report.
By the way, this bug is extremely rare, but a lot less rare for one particular customer who has the worlds slowest internet (luck me - I now have a test environment).
So on the client I have code a bit like this...
procedure DoCommand(MyIdTCPClient:tIdTCPClient; var DATA:tMemoryStream);
var
Buffer: TBytes;
DataSize: Integer;
CommsVerTest: String;
begin
//Write Data
MyIdTCPClient.IOHandler.Write(DATA.Size);
MyIdTCPClient.IOHandler.Write(RawToBytes(Data.Memory^,DataSize));
//Read back 6 bytes CommsVerTest should always be the same (ie ABC123)
SetLength(Buffer,0); //Clear out buffer
MyIdTCPClient.IOHandler.ReadBytes(Buffer,6);
CommsVerTest:=BytesToString(Buffer);
if CommsVerTest<>'ABC123' then
raise exception.create('Invalid Comms'); //It bugs out here in rare cases
//Get Result Data Back from Server
DataSize:=MyIdTCPClient.IOHandler.ReadLongInt;
Data.SetSize(DataSize); //Report thread is stuck here
MyIdTCPClient.IOHandler.ReadBytes(Buffer,DataSize);
end;
Now when I debug it, I can confirm it bugs out when there are two threads in the middle of this procedure. The main thread stops at the exception. And the report thread is stuck somewhere else in the same procedure.
So, it looks to me like I need to make the procedure above thread safe.
I mean so if the user wants to do something they just have to wait until the report thread finishes.
Arrrgh, I thought my client application was single threaded for sending data to the server!
I think that using TThread would not work - because I don't have access to the thread inside Report Builder. I think I need a tCriticalSection.
I think I need to make the application so that the above procedure can only be run by one thread at a time. Other threads have to wait.
Someone please help with the syntax.
TIdIOHandler has Write() and Read...() overloads for sending/receiving TStream data:
procedure Write(AStream: TStream; ASize: TIdStreamSize = 0; AWriteByteCount: Boolean = False); overload; virtual;
procedure ReadStream(AStream: TStream; AByteCount: TIdStreamSize = -1; AReadUntilDisconnect: Boolean = False); virtual;
You do not need to copy the TMemoryStream contents to an intermediate TIdBytes before sending it, or receive it as TIdBytes before copying it back to the TStream. In fact, there is nothing in in the code you have shown that needs to use TIdBytes directly at all:
procedure DoCommand(MyIdTCPClient: TIdTCPClient; var DATA: TMemoryStream);
var
CommsVerTest: String;
begin
//Write Data
MyIdTCPClient.IOHandler.Write(DATA, 0, True);
//Read back 6 bytes CommsVerTest should always be the same (ie ABC123)
CommsVerTest := MyIdTCPClient.IOHandler.ReadString(6);
if CommsVerTest <> 'ABC123' then
raise exception.create('Invalid Comms');
//Get Result Data Back from Server
DATA.Clear;
MyIdTCPClient.IOHandler.ReadStream(DATA, -1, False);
end;
With that said, if you have multiple threads writing to the same socket at the same time, or multiple threads reading from the same socket at the same time, they will corrupt each other's data (or worse). You need to synchronize access to the socket, such as with a critical section at a minimum. Because of your multi-threaded use of TIdTCPClient, you really need to re-think your overall client design.
At the very least, using your existing logic, when you need to send a command and read a response, stop the timer and wait for any pending data to be exchanged before then sending the command, and do not allow anything else to access the socket until the response comes back. You are trying to do too much at one time without synchronizing everything to avoid overlaps.
In the long run, it would be much safer to do all of the reading from a single dedicated thread and then pass any received data to your other threads for processing as needed. But that also means changing your sending logic to match. You could either:
If your protocol allows you to have multiple commands in flight in parallel, then you can send a command from any thread at any time (just be sure to use a critical section to avoid overlaps), but do not wait for a response immediately. Let each sending thread move on and do other things, and have the reading thread notify the appropriate sending thread asynchronously when the expected response actually arrives.
If the protocol does not allow for parallel commands, but you still need each sending thread to wait for its respective response, then give the socket thread a thread-safe queue that other threads can push commands into when needed. The socket thread can then run through that queue periodically sending each command and receiving its response one at a time as needed. Each thread that puts a command into the queue can include a TEvent to be signaled when the response arrives, that way they enter efficient sleep states while waiting, but you preserve your per-thread waiting logic.
Thanks Remy.
The TCriticalSection solved the problem. I have no control over things like the 3rd party report builder. And running reports entirely in their own thread wouldn't make much difference - they still need to share the same connection (I don't want or need parallel connections). Anyway the bulk of the program runs in the main thread, and it is rare that two threads need to communicate with the server at the same time.
So TCriticalSection was perfect - it prevented this procedure running twice at the same time (ie one thread has to wait until the first is finished). And happily - it worked brilliantly.
Basically the code now looks like this:
procedure DoCommand(
CS:tCriticalSection;
MyIdTCPClient:tIdTCPClient;
var DATA:tMemoryStream);
var
Buffer: TBytes;
DataSize: Integer;
CommsVerTest: String;
begin
CS.Enter; //enter Critical Section
try
//Write Data
MyIdTCPClient.IOHandler.Write(DATA.Size);
MyIdTCPClient.IOHandler.Write(RawToBytes(Data.Memory^,DataSize));
//Read back 6 bytes CommsVerTest should always be the same (ie ABC123)
SetLength(Buffer,0); //Clear out buffer
MyIdTCPClient.IOHandler.ReadBytes(Buffer,6);
CommsVerTest:=BytesToString(Buffer);
if CommsVerTest<>'ABC123' then
raise exception.create('Invalid Comms');
//Get Result Data Back from Server
DataSize:=MyIdTCPClient.IOHandler.ReadLongInt;
Data.SetSize(DataSize);
MyIdTCPClient.IOHandler.ReadBytes(Buffer,DataSize);
finally
cs.Leave;
end;
end;

Is safe and good design AllocateHWND to respond more than one thread?

It's known that, in cases when one needs comunicate between UI thread and working thread, an hidden window must be created because of thread safety(handle reconstruction).
For exemplify:
Form1 has N dynamicaly created TProgressBar instances with the same name of a background running .
Is always garanteed that WM_REFRESH will only be called inside Task Thread.
Form1 has H : THandle property that allocates the following procedure:
procedure RefreshStat(var Message: TMessage); message WM_REFRESH;
Inside RefreshStat, in cases when there is only 1 background thread I could easily use L and W parameter to map Task Id and position.
I don't know if the title says what I want to know, but let's imagine if we have an application that has multiple background tasks running.
In my case I use TProgressBar to report progress the done.
Does AllocateHwnd garantee that all messages arrives with no race condition the hidden window?
What happens if two or more tasks post the message at the same time?
If this needs to be controled manually, I wonder if there is something else to do besides creating another message loop system in the custom message.
I hope the question is clear enough.
The message queue associated with a thread is a threadsafe queue. Both synchronous and asynchronous messages from multiple other thread are delivered safely no harmful date races. There is no need for any external synchronization when calling the Windows message API functions like SendMessage and PostMessage.
If two threads post or send messages to the same window at the same time, then there is no guarantee as to which message will be processed first. This is what is known as a benign race condition. If you want one message to be processed before the other then you must impose an ordering.

Qt app crashes on deleting executed task

I have multithread server (inherits QTcpServer). When new connection appears, I create new task (inherits QRunnable), passing socket descriptor to constructor and push this task to QThreadpool (have 3 workers).
QThreadPool::globalInstance()->start(task);
In run() I dynamically create QTcpSocket, set socket descriptor and read first received byte. Based on value of this byte I create new specific task (also inherits QRunnable), passing to its ctr pointer to earlier created QTcpSocket object, and also push this task to QThreadpool.
This specific task make some routine and app crashes.
From log file, I see destructor of this specific task was called.
Also Qt Creator throws next error message:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x18c62290), parent's thread is QThread(0x18c603e0), current thread is QThread(0x18cc3b60)
QSocketNotifier: socket notifiers cannot be disabled from another thread
ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 18cc3b60. Receiver '' (of type 'QNativeSocketEngine') was created in thread 18c603e0", file kernel/qcoreapplication.cpp, line 420
I found similar posts but unfortunately I could not understand how to fix my problem.
Please, help me.
You cannot use QTcpSocket from two different threads, because QObjects are not thread-safe.
You've created your QTcpSocket in the first task, so it "lives" in the thread associated with that task. If you pass its pointer into another QRunnable, then a second thread will try to access it, which will break things.
You'll need to redesign your app in a way that doesn't share the same QTcpSocket between different threads. One possibility is to implement different specific functions in your original task, and simply select the appropriate function based on the first received byte

Resources