I found many answers say that accessing Qt Gui Widgets from another thread is not safe. I agree with this if we try to modify the widgets. But what if I only read the value of widget, without any modification?
I have designed a GUI tool using Qt, and my working thread reads Widgets directly, for example, get the text of QLineEdit, get the value of QComboBox,etc. And I haven't found any problem.
I pass the pointer of MainWindow to working thread.
Is this really not safe?
First: It is always a bad idea to read properties from another thread without protecting the memory (Mutex, Signal & Slot).
Your situation: If nothing wants to change the value, you should be fine. There are no problems if every thread only reads the value. But if you change the value of the QComboBox (for example) by clicking arrow up, arrow down or selecting a new item (what I expect you will do, because that's the reason of using a QComboBox) the value will be written and then the application can crash if your worker thread wants to read the value in the exact same moment (the possibility of a carsh depends on the frequenz your thread pulls the informations).
Your application never crashed because the condition never appeared.
But that does not mean that this can not happen.
Related
I routinely pass the main form handle to other threads so that they can post messages back to the main thread. I saw that on Sept 28, 2013, Remy Lebeau stated:
...the TWinControl.Handle property is not thread-safe, either. You
should use the TApplication.Handle property instead, or use
AllocateHWnd() to create your own window.
in this answer to a question about passing strings.
How is the handle property not safe? Does it change during the life of the program?
How is the Handle property not safe?
When you access the Handle property, if the window handle has not been created, then it is created on demand. If you access the Handle property from a thread other than the GUI thread, then this means you create the window on the wrong thread.
Does it change during the life of the program?
Yes, the window handle can change if the window is re-created.
I routinely pass the main form handle to other threads so that they can post messages back to the main thread.
In this case, you are probably not accessing the Handle property away from the main thread. It sounds like (although I cannot see your code) you are accessing Handle on the main thread and passing that value to the other thread.
However, window recreation is the problem for you. Since your window is subject to recreation, you simply cannot rely on that handle outliving your thread. Whether or not your window will ever be recreated is hard to predict. The VCL does not perform recreation lightly. However, in my view it is far better to be safe than sorry. So, use AllocateHWnd and take control of the lifetime of this window.
I know very similar questions have been asked before, but I am unable to find an answer for my specific problem. I have a main (GUI) thread which upon button press initializes a worker thread to perform some analysis. I am using signals and slots to communicate between my worker thread and my GUI thread (i.e. when the thread starts and when it finishes), but I need to go deeper than that. My worker thread actually calls another class in a separate implementation file which then iterates through a series of calculations which are sent to std::cout for each iteration (as the code used to be a console application for which I am now writing a GUI). I am trying to feed those outputs for each iteration back into my GUI thread so that my text browser is updated in real time as my code iterates. The problem is, when I emit a signal from the class my worker thread calls, it is not picked up by the GUI thread. I do not get any errors. Does anyone have any suggestions on how to transmit a signal to the GUI from a class that my worker thread is calling? I can post code as required, but I'm not sure what would be most helpful to see and my code is quite extensive (it's an aircraft performance application). Any help would be greatly appreciated. Thank you kindly!
1) Make sure the connect() call for connecting you signal returns true. If it does not, qdebug output usually tells you what is wrong
2) You should use the QueuedConnection type (the default (Auto) should work also)
I'm new to development on Windows Phone 7 and Silverlight but I do have experience in win32 and threading in general.
Here's my question:
I am trying to "synchronize" the UI thread w/ another thread that seems to be used by the API's of the object that I am working with. In other words, I would like to make sure that before the user dismisses the current XAML page by pressing the back button, the object that I am working with, which is part of the C# class behind the XAML page is deallocated.
The reason for that is that if I have the deallocation code in the NavigatedFrom handler, the UI thread may attempt to release the object WHILE it is in fact used by the other thread. Therefore, I do have to somehow synchronize the deallocation of this object.
Ideally, when the user presses the back button on the phone, all I do is set a flag "quit" to true to indicate that the user intends to exit. The methods used by the object that are running on another thread, would "see" that this flag is set and then would BeginInvoke*emphasized text* the deallocation code of the object (only because the object has been allocated on the UI thread so I figured it makes sense to deallocate it on the same thread, not knowing its internal workings.) Finally, it would call NavigationService.GoBack() to ensure 'orderly' exit.
Unfortunately, I don't see a way of preventing the XAML page to be dismissed when the user presses the back button although I did override the NavigatedFrom and OnBackKeyPress methods. Even though they contain no code at all, the XAML page is dismissed anyway.
Another thing that is interesting and I would appreciate your comments on this, is that I have a timer (System.Windows.Threading.DispatchTimer). Would this timer be associated only with the C# class behind a XAML page that defines it? In other words, is there a concept of a "message pump" associated with each XAML pages or is there just one message pump for the UI thread that basically is used by ALL XAML pages ? I am asking this because although I dismiss the XAML page whose C# class defines the timer, it seems to still be running.
Thank you.
The reason for that is that if I have the deallocation code in the NavigatedFrom handler, the UI thread may attempt to release the object WHILE it is in fact used by the other thread. Therefore, I do have to somehow synchronize the deallocation of this object.
Not really a problem. If you queue the navigation on the Dispatcher as well, you don't get any NullReferenceExceptions.
Simply use Dispatcher.BeginInvoke(() => NavigationService.Navigate(...)) for safe navigation.
Would this timer be associated only with the C# class behind a XAML page that defines it?
If you by "class" means "ViewModel", then yes, it most definitively should be in the ViewModel.
My UI is using QTreeView with QFileSystemModel to be able to select folders and files. The documentation for QFileSystemModel says that file structure update is done on a seperate thread which would mean the UI would not be blocked. However, this is not the case for me and I can't figure out the discreptency and how other people are not running into this issue. After debugging, I noticed that QFileSystemModel _q_fileSystemChanged slot which takes most of the time is still executed on the main UI thread which makes sense. The Questiong is how does the documentation claim than that it will not block the UI. Is there a solution? Am I misunderstanding something?
To repro
- Create a QTreeView with QFileSystemDataModel
- Set root path to "" or "/"
- Set breakpoint in QFileSystemModel _q_fileSystemChanged slot
- Expand one of the drives after app loads
Problem:
- The slot is called on the UI thread thus blocking the app until it finishes.
There are ways to make the file parser faster, but it I really need to execute on a seperate thread and notify when the data is populated and ready for QTreeView.
Thanks,
Innokenty
I think the reason for this could be the icons. Within the _q_fileSystemChanged() slot fileInfoGatherer.getInfo() gets called which - among other things - resolves the icons for the paths. In it's current design QFileIconProvider uses QIcon to represent icons and QIcon can only be used in the UI thread. QImage seems to be the only class allowed to use in other threads, but I think it may be to expensive to use QImage in the background thread and convert it to an QIcon in the UI thread.
So it is possible that the platform implementation of QFileIconProvider is slow on network paths under some circumstances and therefore slows down the UI main thread.
I don't know if this is the source of your problem, but at least this should be the reason why _q_fileSystemChanged() is called within the UI thread.
I have a multi-threaded Delphi 6 Pro application that I am currently working on heavily. If I set a breakpoint on any code that runs in the context of the Main thread (VCL thread) I don't have any problems. However, if a breakpoint is triggered on any code in one of my other threads, after I continue the application from the breakpoint, all repaints to the VCL components on the main thread (including the main form) don't happen anymore. The application isn't dead because other background code keeps running, just the main thread. It's as if the windows message dispatcher has been corrupted or rendered dormant.
Note, in this application I allocate my own WndProc() via allocateHwnd() on the main form because I need to catch certain registered messages. From that WndProc() I dispatch any custom messages I handle and if the current message is not handled by my code, I pass the message on by calling the main form's inherited WndProc(). If I do handle the current message I simply return from my WndProc() with Msg.Result set to 1 to tell the dispatcher that the message was handled. I can't simply override the TForm WndProc() instead of allocating my own WndProc() because for some reason the Delphi VCL does not pass through registered messages instantiated with the Windows API RegisterWindowMessage() call.
Has anybody experienced this in similar context and if so, what did you do to fix it?
-- roscherl
Since you call AllocateHWnd, that means you've created another window. You mustn't just take the messages that were addressed to that window and forward them to your form's window. Doing that, you're bound to screw things up in your program, although I'm not sure exactly how. Painting problems sound plausible. You should make sure it's really just painting problems and not that your main thread is still suspended. The debugger should be able to tell you that. (You should call DefWindowProc to make your allocated window handle messages you're not prepared to handle yourself. And returning 1 doesn't tell the dispatcher anything; the dispatcher doesn't care — whoever called SendMessage wants to know the result.)
I promise you that forms are completely capable of receiving registered window messages. Override WndProc or assign a new value to the WindowProc property (and remember to save the old value so you can call it after handling your own messages). The source of your problem lies elsewhere.
UPDATE: I'm not saying the way I got past the problem is a good solution. I need to take Rob Kennedy's notes and do some refactoring. However, to get past the problem for now I gave the thread it's own Window and WndProc() and at the top of the thread Execute loop I have a PeekMessage() while loop with calls to TranslateMessage() and DispatchMessage(). I no longer have a problem with setting breakpoints in the thread, but obviously this compounding of WndProc() methods indicates a structural problem in my code. I wanted to add this reply to fill out the discussion. I'm hoping that once I put Rob's suggestions to work when I clean up my WndProc() methods on the relevant forms, especially the main form, I can get rid of the this new WndProc() that I just added to the thread.
Robert.