views:

1299

answers:

6

I'm importing a portion of existing code into my Qt app and noticed a sleep function in there. Now after doing some researching I read that this type of function has no place in event programming. What should I do instead? Also, I am aware of QThread::sleep() [static protected] and subclassing it but I heard thats a hack and ends up doign the same thing. I am thinking trolltech had a reason to not offer easy access to sleep.

I would like to add this: I use the sleep between sending a UDP packet and receiving it. Also in all of this I see your points and I see one area where I will probably implement this but I think I found a situation where using sleep is not a problem and is my case for 95% of the program. First, lets say you have the main window. You click on a menu option to open up a window. The only time UDP packet will be read/writeen is after clicking on the menu option and before the desired window is displayed. Then there are no transfers for the entire time the window is open. At the end, the user presses SAVE and only then do we use UDP to send info back through UDP. So I hope you agree with me that this shouldnt create any problems. The only case I have found to not follow this is in only one of the many windows and it is a screen that displays data that is periodically refreshed ie every second a remote device is polled through UDP and this data is assigned to the views. So for this case I would understand, but its implemented and I havent seen any problems, oh and in any case these calls are in a separate thread and the the Main thread and QThread doesnt enable anything graphics related.

So after this analysis and your good info I would say the answer is: depends what you are doing.

+3  A: 

It isn't pretty but I found this in the Qt mailing list archives:

The sleep method of QThread is protected, but you can expose it like so:

class SleeperThread : public QThread
{
public:
    static void msleep(unsigned long msecs)
    {
        QThread::msleep(msecs);
    }
};

Then just call:

SleeperThread::msleep(1000);

from any thread.

However, a more elegant solution would be to refactor your code to use a QTimer - this might require you saving the state so you know what to do when the timer goes off.

Rob
yeah I was aware of those methods and the class SleeperThread seems the better choice but I am evaluating if using sleep in the main thread is valid practice since it seems to go against event-programming practice.
yan bellavance
It isn't good practice IMHO - you should use the Qt UDP socket class that uses signals and slots so you *know* when there is data to read and when it is safe to write, etc.
Rob
Good point. But now I am thinking this would require me to greatly fragment my code. For instance. I call getUDPdata(COMMAND_BYTE) in which the packet is sent and a reply is received. On the lines of code following that I use this data. If I am to do as you say then I would have to rdo the whole program and things would get very complicated wouldnt you say?
yan bellavance
I think that hard-coded sleeps - in the hope that there will be data ready to read afterwards - is a bad idea and will bite you on the backside eventually. I'd refactor the code if possible.
Rob
+4  A: 

The reason why sleep is a bad idea in event based programming is because event based programming is effectively a form on non-preemptive multitasking. By calling sleep, you prevent any other event becoming active and therefore blocking the processing of the thread.

In a request response scenario for udp packets, send the request and immediately wait for the response. Qt has good socket APIs which will ensure that the socket does not block while waiting for the event. The event will come when it comes. In your case the QSocket::readReady signal is your friend.

If you want to schedule an event for some point of time in the future, use QTimer. This will ensure that other events are not blocked.

doron
well I have completed the program in Linux with the usleep function and I dont have any problems. The call to usleep is in one function only for the whole program. Also I am seeing a problem with all of this. If I have a signal telling me to do a task and in that task I have to do multiple UDP reads and writes then my slot will have to do processing till the first read or write then quit then wait for a another signal to continue the task thencontinue the task in a new slot rinse and repeat....wow I must be missing something. also its not rare that I have a for loop with udp transactions.
yan bellavance
or I would need a state variable and re-emit the same signal....which would still be awkward in the for loops. In any events this seems to me like useless fragmentation that could be replaced by some sort of optimization of event based programming.
yan bellavance
As mentioned sleep or usleep will block the event loop rendering the GUI dead. This means that the user will not be able to cancel the operation or even cleanly exit the application. The correct way to do this is using a state-machine http://en.wikipedia.org/wiki/Finite-state_machine. Welcome to the world of event driven programming.
doron
+2  A: 

I don't know how the QTs handle the events internally, but on most systems at the lowest level the application life goes like this: the main thread code is basically a loop (the message loop), in which, at each iteration, the application calls a function that gives to it a new message; usually that function is blocking, i.e. if there are no messages the function does not return and the application is stopped.

Each time the function returns, the application has a new message to process, that usually has some recipient (the window to which is sent), a meaning (the message code, e.g. the mouse pointer has been moved) and some additional data (e.g. the mouse has been moved to coords 24, 12).

Now, the application has to process the message; the OS or the GUI toolkit usually do this under the hood, so with some black magic the message is dispatched to its recipient and the correct event handler is executed. When the event handler returns, the internal function that called the event handler returns, so does the one that called it and so on, until the control comes back to the main loop, that now will call again the magic message-retrieving function to get another message. This cycle goes on until the application terminates.

Now, I wrote all this to make you understand why sleep is bad in an event driven GUI application: if you notice, while a message is processed no other messages can be processed, since the main thread is busy running your event handler, that, after all, is just a function called by the message loop. So, if you make your event handler sleep, also the message loop will sleep, which means that the application in the meantime won't receive and process any other messages, including the ones that make your window repaint, so your application will look "hang" from the user perspective.

Long story short: don't use sleep unless you have to sleep for very short times (few hundreds milliseconds at most), otherwise the GUI will become unresponsive. You have several options to replace the sleeps: you can use a timer (QTimer), but it may require you to do a lot of bookkeeping between a timer event and the other. A popular alternative is to start a separate worker thread: it would just handle the UDP communication, and, being separate from the main thread, it would not cause any problem sleeping when necessary. Obviously you must take care to protect the data shared between the threads with mutexes and be careful to avoid race conditions and all the other kind of problems that occur with multithreading.

Matteo Italia
got to leave work but i will be sure to read you post later on tonight ;)
yan bellavance
+1  A: 

I don't recommend sleep in a event based system but if you want to ...
You can use a waitcondition, that way you can always interrupt the sleep if neccesary.

//...
QMutex dummy;
dummy.lock();
QWaitCondition waitCondition;
waitCondition.wait(&dummy, waitTime);
//...
TimW
+1  A: 

It is not necessary to break down the events at all. All I needed to do was to call QApplication::processEvents() where sleep was and this prevents the GUI from freezing.

yan bellavance
A: 

Wouldn't this QTime solution fail at midnight?

Robert
yes it would. A better solution would be a QWaitCondition or something of the sort.
yan bellavance