Qt thread call issues - multithreading

Please help me. I am struck-up with thread concept. Actually my problem : I want to display the cities List in the combobox. I am getting cities list from the webservice. I am using thread for update the combo box value after webserice call finished.
Here I can call the webservice. But I couldn't get the Reply.
I am using the following code.
MainWindow.cpp:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
CGNetwork *cgNetwork = new CGNetwork();
ui->setupUi(this);
renderThread = new RenderThread(cgNetwork);
renderThread->start();
connect(renderThread,SIGNAL(finished()),this,SLOT(initControls()));
}
void MainWindow::initControls()
{
CGMainWindowUtility *pointer = CGMainWindowUtility::instance();
QStringList cityitems;
cityitems <<tr("All");
cityitems.append(pointer->getCityList());
QStringListModel *cityModel = new QStringListModel(cityitems, this);
ui->cityComboBox->setModel(cityModel);
}
RenderThread.cpp:
RenderThread::RenderThread(CGNetwork *cgnetwork)
{
cityUrl = "http://112.138.3.181/City/Cities";
categoryUrl = "http://112.138.3.181/City/Categories";
}
void RenderThread::run()
{
qDebug()<< "THREAD Started";
CGNetwork *cgnetworks = new CGNetwork();
cgnetworks->getCityList(cityUrl);
}
CGNetwork.cpp:
void CGNetwork ::getCityList(const QUrl url)
{
cityGuideNetworkAccessManager = new QNetworkAccessManager(this);
qDebug()<<"connection";
connect(cityGuideNetworkAccessManager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(parseCityList()));
const QNetworkRequest cityRequest(url);
cityReply= cityGuideNetworkAccessManager->get(cityRequest);
connect(cityReply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(slotError()));
}
void CGNetwork::parseCityList()
{
qDebug()<<"Parsing";
cgParser = new CGJsonParser();
cgParser->CityRead(cityReply);
}

Since QNetworkAccessManager works asynchronously, there's no need for a separate thread. You can call getCityList directly from your main thread and it won't block.
I think your slots weren't called because your QThread::run returned before any of the work its been doing had a chance to complete, since getCityList just initiated an http request without waiting for it (because QNetworkAccessManager::get doesn't block like I said above).
Also as a side note, your slots aren't getting the same parameters as their corresponding signals, I don't remember if Qt supports this.

Related

Getting value from thread running in while loop

I have a java thread which is running a path-finding algorithm in a constant while loop. Then, every so often I want to retrieve the most updated path from the thread. However, I am unsure how to do this, and think I might be doing it wrong.
My thread consists of the following code:
public class BotThread extends Thread {
Bot bot;
AStar pathFinder;
Player targetPlayer;
public List<boolean[]> plan;
public BotThread(Bot bot) {
this.bot = bot;
this.plan = new ArrayList<>();
pathFinder = new AStar(bot, bot.getLevelHandler());
}
public void run() {
while (true) {
System.out.println("THREAD RUNNING");
targetPlayer = bot.targetPlayer;
plan = pathFinder.optimise(targetPlayer);
}
}
public boolean[] getNextAction() {
return plan.remove(0);
}
}
I then create an object of BotThread, and call start(). Then when I call getNextAction() on the thread, I seem to receive a null pointer. Is this because I am not able to call another method on the thread whilst it is in the main loop? How should I do this properly?
This is because you are not giving enough time to thread to initialise plan Arraylist. You need to add sleeping time to the threads. Something like this while calling BotThread class from main:
int num_threads = 8;
BotThread myt[] = new BotThread[num_threads];
for (int i = 0; i < num_threads; ++i) {
myt[i] = new BotThread();
myt[i].start();
Thread.sleep(1000);
myt[i].getNextAction();
}

Multithreaded program hangs on control method call

I've got a UI with 2 buttons and a textbox.
When the user presses the "Receive" button, a thread is started for an infinite work loop (receiving and printing messages from multicast). When the user presses the "Stop" button, the thread is given it's "kill flag" and then the program waits for the Join() to finish.
That infinite work loop calls back to the UI textbox with a SetTextBoxText(System::String) method. This is causing a race condition. Sometimes, the thread finishes the Join() just fine. Others, the program hangs forever on the Join().
I believe this is because when the UI thread calls Join() on its work thread, the work thread may be in the middle of its loop and is trying to invoke a locked thread. The UI thread is waiting for the Join() and is unable to do anything (like SetTextBoxText).
So, race-condition or deadlock, I need a way to check if the control is usable. If it is, then call the method to print like normal. If it is not usable, then don't try to call the SetTextBoxText method and continue like normal.
Code time, I'm actually using a UserControl, not a separate textbox, button1, and button2. I call the UserControl "MyUserControl". It contains the following code:
System::Void MyUserControl::buttonReceive_Click(System::Object^ sender, System::EventArgs^ e)
{
//each MyUserControl has their own myThread
this->myThread = gcnew System::Threading::Thread(gcnew System::Threading::ThreadStart(this, &MyUserControl::WorkLoop));
this->workLoopFlag = true;
this->myThread->Start();
}
void MyUserControl::WorkLoop()
{
while (this->workLoopFlag == true)
{
System::Threading::Thread::BeginCriticalRegion();
//this->myThread->BeginCriticalRegion();
Process();
//this->myThread->EndCriticalRegion();
System::Threading::Thread::EndCriticalRegion();
}
}
void EntityStatePduProcessor::Process()
{
//These 2 lines are for getting the correct MyUserControl to edit. Stored in GlobalVars::myList
ThreadPredicate^ threadPred = gcnew ThreadPredicate(System::Threading::Thread::CurrentThread->ManagedThreadId);
UserControlDataCollection^ userControlDataColl = GlobalVars::myList->Find(gcnew System::Predicate<UserControlDataCollection^>(threadPred, &ThreadPredicate::IsMatch));
System::Threading::Thread::BeginCriticalRegion();
if (userControlDataColl != nullptr) //should only happen after killing a thread
{
MyUserControl^ controlToEdit = (MyUserControl^)System::Windows::Forms::Control::FromHandle(userControlDataColl->control);
if (controlToEdit != nullptr)
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
controlToEdit->SetTextBoxConsoleText("a system::string to place into the textbox");
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
else
{
System::Windows::Forms::MessageBox::Show("controlToEdit == nullptr");
}
}
System::Threading::Thread::EndCriticalRegion();
}
delegate void MyStringDelegate(System::String ^ text);
void MyUserControl::SetTextBoxConsoleText(System::String^ input)
{
if (this->InvokeRequired) // (this->consoleTextBox->InvokeRequired)
{
MyStringDelegate^ myStrDel = gcnew MyStringDelegate(this, &MyUserControl::SetTextBoxConsoleText);
this->Invoke(myStrDel, gcnew array<Object^> { input });
}
else
{
this->textBoxConsole->Text = input;
this->textBoxConsole->Refresh();
}
}
System::Void MyUserControl::buttonStop_Click(System::Object^ sender, System::EventArgs^ e)
{
this->workLoopFlag = false; // kill the endless while loop
this->myThread->Join();
}
I tried to post the code in chronological order and only include the essentials while explaining the gaps in //comments.
The code that causes the hang is in the 3rd method shown Process() outlined with //~~~.
How do I correctly ensure that the controlToEdit is still able to access and not just waiting on a Join()?

Vala Threading: invocation of void method not allowed as expression

Hey i've been writing an application in which i need to create thread to perform background tasks while the GUI is being loaded. However no matter that i do i can find a way around this error:
error: invocation of void method not allowed as expression
Thread<void> thread = new Thread<void>.try("Conntections Thread.", devices_online(listmodel));
The line in question is the creating of a new thread which calls the "devices_online" method.
The Full code which is being effected is:
try {
Thread<void> thread = new Thread<void>.try("Conntections Thread.", devices_online(listmodel));
}catch(Error thread_error){
//console print thread error message
stdout.printf("%s", thread_error.message);
}
And Method is:
private void devices_online(Gtk.ListStore listmodel){
//clear the listview
listmodel.clear();
//list of devices returned after connection check
string[] devices = list_devices();
//loop through the devices getting the data and adding the device
//to the listview GUI
foreach (var device in devices) {
string name = get_data("name", device);
string ping = get_data("ping", device);
listmodel.append (out iter);
listmodel.set (iter, 0, name, 1, device, 2, ping);
}
}
Ive done so much Googleing but Vala isn't exactly the most popular language. Any help?
Like the compiler error says, you are getting a void by calling a method. Then you are trying to pass the void value into the thread constructor.
Thread<void> thread = new Thread<void>
.try ("Conntections Thread.", devices_online (listmodel));
The second cunstructor argument of Thread<T>.try () expects a delagate of type ThreadFunc<T> which you are not satisfying.
You are confusing a method call with a method delegate.
You can pass an anonymous function to fix that:
Thread<void> thread = new Thread<void>
.try ("Conntections Thread.", () => { devices_online (listmodel); });

Set DocumentViewer.Document from another thread?

I have a class with a method (CreateDocument) that fires an event at the end. The event args contain a FixedDocument. In my MainWindow code I try to set a DocumentViewer's Document like:
void lpage_DocCreated(object sender, LabelDocumentEventArgs e)
{
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new DispatcherOperationCallback(delegate
{
FixedDocument fd = e.doc;
documentViewer1.Document = fd;
documentViewer1.FitToWidth();
return null;
}), null);
}
I receive "The calling thread cannot access this object because a different thread owns it." on line documentViewer1.Document = fd;
I am able to update a progress bar in another event handler that the same method fires while it is working:
Int32 progress = Int32.Parse(sender.ToString());
progBar.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
new DispatcherOperationCallback(delegate
{
progBar.Value = progress;
return null;
}), null);
I can't figure out why I can't set the document when I'm essentially doing the same type of thing when I set the progress bar value.
The FixedDocument element also has thread-affinity. So if you are creating it in a separate thread than the documentViewer1, then you would get that exception.
Basically, anything that derives from DispatcherObject has a thread-affinity. FixedDocument derives from DispatcherObject, just like the viewer controls.

How do I block access to a method until animations are complete

I have a Silverlight app. that has a basic animation where a rectangle is animated to a new position. The animation consists of two DoubleAnimation() - one transforms the X, the other transforms the Y. It works OK.
I basically want to block any other calls to this animate method until the first two animations have completed. I see that the DoubleAnimation() class has a Completed event it fires but I haven't been successful in constructing any kind of code that successfully blocks until both have completed.
I attempted to use Monitor.Enter on a private member when entering the method, then releasing the lock from one of the animations Completed event, but my attempts at chaining the two events (so the lock isn't released until both have completed) haven't been successful.
Here's what the animation method looks like:
public void AnimateRectangle(Rectangle rect, double newX, double newY)
{
var xIsComplete = false;
Duration duration = new Duration(new TimeSpan(0, 0, 0, 1, 350));
var easing = new ElasticEase() { EasingMode = EasingMode.EaseOut, Oscillations = 1, Springiness = 4 };
var animateX = new DoubleAnimation();
var animateY = new DoubleAnimation();
animateX.EasingFunction = easing;
animateX.Duration = duration;
animateY.EasingFunction = easing;
animateY.Duration = duration;
var sb = new Storyboard();
sb.Duration = duration;
sb.Children.Add(animateX);
sb.Children.Add(animateY);
Storyboard.SetTarget(animateX, rect);
Storyboard.SetTargetProperty(animateX, new PropertyPath("(Canvas.Left)"));
Storyboard.SetTarget(animateY, rect);
Storyboard.SetTargetProperty(animateY, new PropertyPath("(Canvas.Top)"));
animateX.To = newX;
animateY.To = newY;
sb.Begin();
}
EDIT (added more info)
I ran into this initially because I was calling this method from another method (as it processed items it made a call to the animation). I noticed that the items didn't end up where I expected them to. The new X/Y coordinates I pass in are based on the items current location, so if it was called multiple times before it finished, it ended up in the wrong location. As a test I added a button that only ran the animation once. It worked. However, if I click on the button a bunch of times in a row I see the same behavior as before: items end up in the wrong location.
Yes, it appears Silverlight animations are run on the main UI thread. One of the tests I tried I added two properties that flagged whether both animations had completed yet. In the AnimateRectange() method I checked them inside of a while loop (calling Thread.Sleep). This loop never completed (so it's definitely on the same thread).
So I created a queue to process the animations in order:
private void ProcessAnimationQueue()
{
var items = this.m_animationQueue.GetEnumerator();
while (items.MoveNext())
{
while (this.m_isXanimationInProgress || this.m_isYanimationInProgress)
{
System.Threading.Thread.Sleep(100);
}
var item = items.Current;
Dispatcher.BeginInvoke(() => this.AnimateRectangle(item.Rect.Rect, item.X, item.Y));
}
}
Then I call my initial routine (which queues up the animations) and call this method on a new thread. I see the same results.
As far as I am aware all of the animations in Silverlight are happening on the UI thread anyway. I am guessing that only the UI thread is calling this animation function anyway, so I am not sure that using locking will help. Do you really want to be blocking the entire thread or just preventing another animation from starting?
I would suggest something more like this:
private bool isAnimating = false;
public void AnimateRectangle(Rectangle rect, double newX, double newY)
{
if (isAnimating)
return;
// rest of animation code
sb.Completed += (sender, e) =>
{
isAnimating = false;
};
isAnimating = true;
sb.Begin();
}
Just keep track of whether or not you are currently animating with a flag and return early if you are. If you don't want to lose potential animations your other option is to keep some kind of a queue for animation which you could check/start when each animation has completed.
This question really peaked my interest. In fact I'm going to include it in my next blog post.
Boiling it down, just to be sure we are talking about the same thing, fundementally you don't want to block the call to AnimateRectangle you just want to "queue" the call so that once any outstanding call has completed its animation this "queued" call gets executed. By extension you may need to queue several calls if a previous call hasn't even started yet.
So we need two things:-
A means to treat what are essentially asynchronous operations (sb.Begin to Completed event) as a sequential operation, one operation only starting when the previous has completed.
A means to queue additional operations when one or more operations are yet to complete.
AsyncOperationService
Item 1 comes up in a zillion different ways in Silverlight due to the asynchronous nature of so many things. I solve this issue with a simple asynchronous operation runner blogged here. Add the AsyncOperationService code to your project.
AsyncOperationQueue
Its item 2 that really took my interest. The variation here is that whilst an existing set of operations are in progress there is demand to add another. For a general case solution we'd need a thread-safe means of including another operation.
Here is the bare-bones of a AsyncOperationQueue:-
public class AsyncOperationQueue
{
readonly Queue<AsyncOperation> myQueue = new Queue<AsyncOperation>();
AsyncOperation myCurrentOp = null;
public void Enqueue(AsyncOperation op)
{
bool start = false;
lock (myQueue)
{
if (myCurrentOp != null)
{
myQueue.Enqueue(op);
}
else
{
myCurrentOp = op;
start = true;
}
}
if (start)
DequeueOps().Run(delegate { });
}
private AsyncOperation GetNextOperation()
{
lock (myQueue)
{
myCurrentOp = (myQueue.Count > 0) ? myQueue.Dequeue() : null;
return myCurrentOp;
}
}
private IEnumerable<AsyncOperation> DequeueOps()
{
AsyncOperation nextOp = myCurrentOp;
while (nextOp != null)
{
yield return nextOp;
nextOp = GetNextOperation();
}
}
}
Putting it to use
First thing to do is convert your existing AnimateRectangle method into a GetAnimateRectangleOp that returns a AsyncOperation. Like this:-
public AsyncOperation GetAnimateRectangleOp(Rectangle rect, double newX, double newY)
{
return (completed) =>
{
// Code identical to the body of your original AnimateRectangle method.
sb.Begin();
sb.Completed += (s, args) => completed(null);
};
}
We need to hold an instance of the AsyncOperationQueue:-
private AsyncOperationQueue myAnimationQueue = new AsyncOperationQueue();
Finally we need to re-create AnimateRectangle that enqueues the operation to the queue:-
public void AnimateRectangle(Rectangle rect, double newX, double newY)
{
myAnimationQueue.Enqueue(GetAnimateRectangleOp(rect, newX, newY)
}

Resources