Using QTcpSocket from multiple threads (Locking/Synchronous approach)
-
Dear all,
I'm developing a library to communicate to an hardware-device using TCP/IP protocol.
I can't use asynchronous approach cause there might not be any QEventLoop on user side application.That hardware is able to manage maximum one TCP/IP connection per time; from user side, this device should be able to communicate from different threads (status, command, ecc...).
My idea is to create a DeviceController class which let user application using that device; to handle different threads, this is the idea:
- For first connection, create a QTcpSocket and track which is its "creator" thread
- for the other threads, I'll create others QTcpSocket and I'll set them the socketDescriptor using setSocketDescriptor method
In this way, I should be able to use QTcpSocket safely from different threads (clearly, cause socketDescriptor is shared among different thread, from user side a locking access is needed).
I know isn't possible to use QTcpSocket from different threads, cause QTcpSocket is neither re-entrant not thread-safe. So the only way to share connection, is sharing its socketdescriptor.Is this a correct solution?
Nicola
-
Christian Ehrlicher Lifetime Qt Championreplied to nico88desmo on last edited by Christian Ehrlicher
@nico88desmo said in Using QTcpSocket from multiple threads (Locking/Synchronous approach):
. Is it correct?
Yes. Or better - simply use signals and slots.
But as you don't like the basic Qt stuff - simply use the underlying socket stuff from the os. -
@nico88desmo Hi,
Why not have your controller as only entry-point to write to the socket ?
Your threads would communicate with your controller and would not need to know anything about that socket. -
Hi, when I have to manage remote tcp (or serial, it is the same) devices I normally use a synchronous approach.
If a plant can have not so much devices (less than 100) I normally use a thread for each connection. If a plant can have thousands of device I normally use a thread that can manage more than one connection.
To use a thread it is more simple when there is a complex state machine.
In other words you can use a thread that can create one or more QTcpSocket objects and to manager it I suggest to use the non blocking methods. -
@SGaist said in Using QTcpSocket from multiple threads (Locking/Synchronous approach):
@nico88desmo Hi,
Why not have your controller as only entry-point to write to the socket ?
Your threads would communicate with your controller and would not need to know anything about that socket.This is the idea: I'd like having that controller which uses the socket: from user side, the only visible things are common methods such as:
- connect()
- disconnect()
- setup connection(..)
@mrdebug said in Using QTcpSocket from multiple threads (Locking/Synchronous approach):
Hi, when I have to manage remote tcp (or serial, it is the same) devices I normally use a synchronous approach.
If a plant can have not so much devices (less than 100) I normally use a thread for each connection. If a plant can have thousands of device I normally use a thread that can manage more than one connection.
To use a thread it is more simple when there is a complex state machine.
In other words you can use a thread that can create one or more QTcpSocket objects and to manager it I suggest to use the non blocking methods.Yes I use a similar approach too: for devices that make multiple connection available, I follow this idea (single connection for each thread = neither concurrent problem, nor mutual access, etc).
The problem for this device is that I can have only a single connection to it; this constraints me to share socket connection to multiple threads (but user doesn't know this, he "sees" just a controller).
So, inside that controller, I'm going to manage this socket object; unfortunately I can't shareQTcpSocket
through different threads, even if it is protected using a mutex; I've tried this solution, but I have some undefined behaviour (sometimes some memory leakage, sometimes access violation): the only feasible way to share aQTcpSocket
is creating a set ofQTcpSockets
, each of them having the samesocketDescriptor
.Unfortunately I haven't seen any deep article about how to use
socketDescriptor
, just this description -
@nico88desmo said in Using QTcpSocket from multiple threads (Locking/Synchronous approach):
I can't use asynchronous approach cause there might not be any QEventLoop on user side application.
This begs further explanation. If the code can create a thread, why can't it create a QThread and use the event loop which that thread provides? I'm skeptical that the event loop provided by the QCoreApplication instance can't be used, but there are situations involving integrating as a plugin that can be painful.
- for the other threads, I'll create others QTcpSocket and I'll set them the socketDescriptor using setSocketDescriptor method
From the documentation forQAbstractSocket::setSocketDescriptor():
Note: It is not possible to initialize two abstract sockets with the same native socket descriptor.
-
@jeremy_k said in Using QTcpSocket from multiple threads (Locking/Synchronous approach):
This begs further explanation. If the code can create a thread, why can't it create a QThread and use the event loop which that thread provides? I'm skeptical that the event loop provided by the QCoreApplication instance can't be used, but there are situations involving integrating as a plugin that can be painful.
The idea to not use a QThread with its event loop is because I don't like so much the idea to use a signal/slot pattern just to read/write data on a socket; but if there isn't any other way, I think I haven't got any choice.
@jeremy_k said in Using QTcpSocket from multiple threads (Locking/Synchronous approach):
From the documentation forQAbstractSocket::setSocketDescriptor():
Note: It is not possible to initialize two abstract sockets with the same native socket descriptor.
That sentence raises my doubts.
So, from what I understand:
- a
QTcpSocket
instance is not shareable among different threads, even if its access is done using a mutual exclusion way - passing the same
socketDescriptor
to differentQTcpSocket
instances is not feasible.
So, if I need to share a
QTcpSocket
on different threads (cause I can't use multiple connections to that device), the only way is moving that socket instance into a dedicated event-loop thread and use signal/slots/invokeMethod/QFuture pattern to read/write from that socket. Is it correct? - a
-
Christian Ehrlicher Lifetime Qt Championreplied to nico88desmo on last edited by Christian Ehrlicher
@nico88desmo said in Using QTcpSocket from multiple threads (Locking/Synchronous approach):
. Is it correct?
Yes. Or better - simply use signals and slots.
But as you don't like the basic Qt stuff - simply use the underlying socket stuff from the os. -
@Christian-Ehrlicher said in Using QTcpSocket from multiple threads (Locking/Synchronous approach):
@nico88desmo said in Using QTcpSocket from multiple threads (Locking/Synchronous approach):
. Is it correct?
Yes. Or better - simply use signals and slots.
But as you don't like the basic Qt stuff - simply use the underlying socket stuff from the os.Between the two solutions, I think I'm going to signal/slot approach ;)
-