Hello kupferstecher,
First of all, sorry for the late response, I was busy with other things.
1. Multithreading
As I understand you add tasks to the task list e.g. within the main thread, the task list is then polled by the TClientThread of the server application. I don't see any protection there when TList.Add is called in order to add a task (E.g. from TfMain.miBroadcastMessageClick via FTCPServer.SendMessage). The task list is accessed in the Execute method of the client thread and first the count property is checked and then in case it is not zero the list is copied to a local TList. That copy sequence is protected in a critical section, but as the list is thread specific, that critical section seems to protect nothing. Or is it just to guarantee a cache flush?
Additionally I wouldn't expect the access to TList.count to be thread safe, but I'm not sure. Can you say something to that data handling concept?
The idea behind TTaskList is that in order to broadcast a message, we have to lock, then loop through the server's client list. If we perform the actual broadcasting from inside the loop, the server will become unresponsive. By using a thread safe TTaskList, we offload the bulk of the work to the execute event of each client, this way minimize the amount of time the list needs to be locked.
Each TClientThread has its own task list, more over there is no data sharing between the different worker threads, so everything is thread safe, except when new task are added from the main thread. As you correctly noticed, the AddTask method should also be wrapped inside a critical section. I will fix this issue soon, but instead of my own critical sections, I will switch to a TThreadList, which is thread safe by default. I should have gone with a TThreadList in the first place. Thanks for noticing this bug!
2. Synapse RecvPacket
You use RecvPacket several times, e.g. in TClientThread.RecvMessage (line 685 of uTCPSockets). I'm not sure about the synapse library, but as far as I understand the TCP-protokoll the incoming data is just a byte stream and not bundled in packets. So when you call RecvPacket how can you be sure that what you receive is the complete data and not only half of a message or several messages combined?
I will quote from Synapse documentations:
Method reads all data waiting for read. If no data is received within
TIMEOUT (in milliseconds) period, @link(LastError) is set to WSAETIMEDOUT.
Methods serves for reading unknown size of data. Because before call this
function you don't know size of received data, returned data is stored in
dynamic size binary string. This method is preffered for reading from
stream sockets (like TCP). It is very goot for receiving datagrams too!
(UDP protocol)}
After a RecvPacket usually I check for errors(FBlockSocket.LastError > 0), so if something went wrong I will know it.