I'm working on a chat application using C and unix low level sockets. I have succeeded in making the console version, but I want to make a GUI for the application.
I would like to use GTK for the GUI.
my problem is how to "synchronize" the socket and the GUI.
because I have to call gtk_main() as the last GTK statement and the application itself is an infinite loop. How can I update the GUI when a message comes in?
You are facing the problem that you have several event systems at once but only one thread. Gtk+ comes with its own event handler, that eventually boils down to a select() which will wake up on any user input or other gtk event. You yourself want to handle networking with your own event handling, which typically consists of a select() on your socket(s) or using the sockets in blocking mode.
One solution is to integrate your events into the event loop of Gtk+.
You can make Gtk+ watch/select() your sockets and call a specific function when their state changes (data readable).
See the section "Creating new source types" on http://developer.gnome.org/glib/2.30/glib-The-Main-Event-Loop.html
Another solution would be to use Gtk+ networking functionality.
Typically you don't want to do something so special with the sockets that it is not easily wrapable with Glib IO Channels. See http://developer.gnome.org/glib/2.30/glib-IO-Channels.html
A third solution is to start a second thread that handles your networking, e.g. with posix threads or Gtk+ threading functionality.
Separating GUI from the worker part of your application is in general a good idea. However for a chat application, it probably does not give any benefit over the other solutions. See http://developer.gnome.org/glib/2.30/glib-Threads.html
This is an example in python with pygobject using GLib.IOChannel to add a watch in the gtk main event loop.
One watch is for listening to new connections.
The other for receiving data.
This is adapted from this pygtk example: http://rox.sourceforge.net/desktop/node/413.html
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib;
from socket import socket
def listener(io, cond, sock):
conn = sock.accept()[0]
GLib.io_add_watch(GLib.IOChannel(conn.fileno()),0,GLib.IOCondition.IN, handler, conn)
return True
def handler(io, cond, sock):
print(sock.recv(1000))
return True
s = socket()
s.bind(('localhost', 50555))
s.listen()
GLib.io_add_watch(GLib.IOChannel(s.fileno()), 0, GLib.IOCondition.IN, listener, s)
Gtk.main()
Related
I have a network application which is listening on multiple sockets.
To handle each socket individually, I use Python's threading.Thread module.
These sockets must be able to run tasks on packet reception without delaying any further packet reception from the socket handling thread.
To do so, I've declared the method(s) that are running the previously mentioned tasks with the keyword async so I can run them asynchronously with asyncio.run(my_async_task(my_parameters)).
I have tested this approach on a single socket (running on the main thread) with great success.
But when I use multiple sockets (each one with it's independent handler thread), the following exception is raised:
ValueError: set_wakeup_fd only works in main thread
My question is the following: Is asyncio the appropriate tool for what I need? If it is, how do I run an async method from a thread that is not a main thread.
Most of my search results are including "event loops" and "awaiting" assync results, which (if I understand these results correctly) is not what I am looking for.
I am talking about sockets in this question to provide context but my problem is mostly about the behaviour of asyncio in child threads.
I can, if needed, write a short code sample to reproduce the error.
Thank you for the help!
Edit1, here is a minimal reproducible code example:
import asyncio
import threading
import time
# Handle a specific packet from any socket without interrupting the listenning thread
async def handle_it(val):
print("handled: {}".format(val))
# A class to simulate a threaded socket listenner
class MyFakeSocket(threading.Thread):
def __init__(self, val):
threading.Thread.__init__(self)
self.val = val # Value for a fake received packet
def run(self):
for i in range(10):
# The (fake) socket will sequentially receive [val, val+1, ... val+9]
asyncio.run(handle_it(self.val + i))
time.sleep(0.5)
# Entry point
sockets = MyFakeSocket(0), MyFakeSocket(10)
for socket in sockets:
socket.start()
This is possibly related to the bug discussed here: https://bugs.python.org/issue34679
If so, this would be a problem with python 3.8 on windows. To work around this, you could try either downgrading to python 3.7, which doesn't include asyncio.main so you will need to get and run the event loop manually like:
loop = asyncio.get_event_loop()
loop.run_until_complete(<your tasks>)
loop.close()
Otherwise, would you be able to run the code in a docker container? This might work for you and would then be detached from the OS behaviour, but is a lot more work!
1. Background info
I'm working in Python 3.7. The python Qt version Pyqt5 enables you to fire custom pyqt signals. For example:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class MyClass(QObject):
mysignal = pyqtSignal(str)
def __init__(self):
super().__init__()
self.mysignal.connect(self.bar)
return
def foo(self):
self.mysignal.emit("foobar")
return
#pyqtSlot
def bar(self, mystr):
print("signal received: {0}".format(mystr))
return
2. The problem
PyQt starts an event listener loop in the main thread: it waits for incoming events on a queue and processes them one-by-one. Most of these events are user-invoked things like pushing a button, clicking something, ...
If you fire pyqt signals programatically, as in the foo() function above, you also push events onto this queue (I think). That shouldn't be a big deal, unless you fire too many pyqt signals in a short burst. The queue is overwhelmed and user events don't get processed in time. The user sees a freezed GUI. Yikes!
3. Solution
One way to tackle this problem could be assigning low priorities to programatically fired pyqt signal. Is this possible? How?
If not - do you know other ways to solve the problem?
In the case of direct connections (sender and receiver in the same thread), the slot will be directly called when you emit your signal.
So, in your example, you can replace your emit by a direct call to self.bar.
But, if your slot is too long, the event loop has to wait before it will be able to process the user events.
If your UI is freezing when you call your slot, that means you should use another thread to let the event loop process user events.
Is there a way to easily determine what slots are connected to a signal or object in PyQt4?
The main use-case for this is connecting all default slots for a given object. For example, maybe I want to enable sorting on a QTableView with setSortingEnabled() but I want to control the horizontalHeader().sortIndicatorChanged signal myself. I need to see what all slots are connected to the sortIndicatorChanged signal and disconnect them.
Ideally I'd like a function like the following:
def print_all_connected(qobject, signal=None):
signals = qobject.signals() if signal is None: else [signal]
for signal in qobject.signals():
for slot in qobject.connectedSlots():
print slot
So a call like print_all_connected(my_table_model, 'dataChanged') would print all the slots connected to the dataChanged signal on the my_table_model slot.
I think standard Qt interprets a call to disconnect() as an automatic disconnection of all slots for the signal it was called on. Unfortunately, I don't think PyQt4 implements this, signals must be disconnected one by one. However, I'd still like to be able to search an object and see what slots or signals it has and print/disconnect them, etc.
In addition, I know there is a QObject.receviers() method that can return the number of 'receivers' connected to a given slot. However, this doesn't tell me who/what those receivers are.
Disconnect works just like in Qt. See the documentation for disconnect in pyQt.
I couldn't find a way to do what you want, but you can check the doku for:
New-style Signal and Slot Support
Old-style Signal and Slot Support
Things to be Aware Of
I access the Qt GUI's QLabel's QPixmap in another thread since I will finally use this to display mjpeg stream in QLabel, and I decided to use QLabel since its the easiest way
It should look like 'Live' and not block the UI thus using another (non-gui) thread.
nothing shows up in the QLabel. only the exception QPixmap: It is not safe to use pixmaps outside the GUI thread
any better or correct way to do this ?
here is my PyQt code of another thread: self.theQlabel.setPixmap(QtGui.QPixmap.fromImage(myQimg)
Instead of directly setting the pixmap, make the external thread emit an updatePixmap signal. Then in the GUI thread, listen to the signal and update the pixamp at that time. Something like that should work (in C++):
// In the GUI thread:
class YourWidget: QObject {
public:
YourWidget();
public slots:
void updatePixmap(const QPixmap& pixmap);
}
YourWidget::YourWidget() {
// Connect to the signal here:
QObject::connect(otherThread, SIGNAL(updatePixmap(const QPixmap&)), this, SLOT(updatePixmap(const QPixmap&)));
}
YourWidget::void updatePixmap(const QPixmap& pixmap) {
// Update the pixmap here in a thread-safe way
}
// In the external thread:
// Emit the signal. The GUI thread will receive it and can then update the pixmap
emit updatePixmap(thePixmap);
I think that it might be dangerous to even create a QPixmap in anything other than the GUI thread. You might want to consider passing a QImage and converting it to a QPixmap in the main thread. I can't find a direct reference to support this assertion, but
http://developer.qt.nokia.com/doc/qt-4.8/thread-basics.html
hints that
All widgets and several related classes, for example QPixmap, don't work in secondary threads.
The email thread at
http://lists.trolltech.com/qt-interest/2008-11/msg00534.html
also seems to agree with me.
Create RAW DirectX/OpenGL OS context into this QLabel's winId() and do whatever you want. I think, this is the best way for high performance HD video, and the ONLY way :) sometimes you just HAVE to use RAW things to achieve the maximum performance and touch the iron in your computer :)
My code is a plugin of a host software which gets limited processing time. Therefore, I create a second thread (via system API) and start QApplication there. That way, the GUI runs smoothly.
Now, I would like to run a QThread event loop in the original such that I could use Signal/Slot (Qt::QueuedConnection) to invoke functions that are not thread safe in the host software.
Is there a way to create such QThread event loop without creating a new thread?
Thanks!
I'm not quit sure if i get you right,
but you can start your own event loop just by calling QEventLoop::exec() on a e.g. private class member.
Don't forget to call QEventLoop.exit().
Bye, Lars