I'm trying to do something very simple:
OK button sums a+b and shows in c
Loop switch button control a infinity loop
Option 1 - Loop outside event
Option 2 - Loop inside event
I just want to be able to keep the loop running and the OK button working at the same time, how can achieve that simple task in Labview "way of life".
Results:
Op 1 - Outside event: One loop occurs after OK click, if loop is running, OK works only at first time
Op 2 - Inside event: Button OK does not work
You can't. You'll need two seperate while loops, one with the count functionality, but don't use the 'loop' variable as the stop condition, make the loop variable control a the count condition.
In the other while loop you'll have your event code.
The only thing you'll have to worry about is stopping the first while loop from the event code.
Here is how you can do it with a Master/Slave configuration. All the user events are handled in the master, the counting is handled in the slave. The loop can be restarted and the stop works for both loops.
To Stop the code you use a different event, in the case the loop conditional is false you don't do anything in the slave loop. Not shown here, but the loop conditional also has it's own event structure to reset the counter if needed.
This master/slave structure is extendable to as many loops as you want.
I see two options:
Similiar to option 2 but do the "loop math" not inside the "Loop Value Canged"-Case but inside the "Timeout"-Case. Then you don't need the while loop, use a if-case (loop = true) instead.
Use two while loops. Inside each of them put a event case. One to handle the "C=A+B"-Event and one for the "Loop Value Changed".
I think the design pattern you are looking for is the Producer/Consumer pattern. This allows you to run parallel loops and if need be share data between them.
A quick google on the term combined with labview will give you enough examples.
Related
Does code below mean anything? If it does, what's the scenario to use it? What's difference if the sleep time is different?
...
while True:
asyncio.get_event_loop().run_until_complete(asyncio.sleep(1))
...
Copy from one comment which I think answered my question:
run_until_complete() runs not only the given task, but also any other runnable tasks, until the given task completes. The above loop could have a meaning if some tasks were scheduled using asyncio.get_event_loop().create_task(xxx) prior to the loop's execution. In that case the while loop as shown might be designed not to run sleep() (which would indeed be useless), but to give the event loop a time slot of 1s to run, and then (presumably in the loop) do some non-asyncio checks.
My problem is this. I have check box which when checked starts while loop. At that while loop there is createprocess function. While checkbox is marked as checked, function repeats it self again and again. Problem is that while loop is running I can't push check box again to change it's values and stop the process. I think that here is needed something like two parallel process working at the same time, but I am not sure. My question would be:
* Is there a way to access my controls while while loop is running?
* Or maybe I should use something else instead of while process?
Suggestions or some kind of example would be appreciated.
The problem is that you are running the loop in the same thread that owns the CheckBox, and that loop is blocking the thread from processing new messages. That is why you are not able to uncheck the CheckBox (or do anything else with your UI).
You need to either:
move the loop to a worker thread. When the CheckBox becomes checked, start the thread. When the CheckBox becomes unchecked, stop the thread. Do not block the dialog's thread at all. This is the best option.
break apart your loop and make it event-driven. When the CheckBox becomes checked, post a custom window message to yourself. When you receive that message, if the CheckBox is still checked then perform one iteration of your loop and then post the message back to yourself again. Repeat until the CheckBox becomes unchecked. This option does not require any threads, but your UI will still be blocked during each individual iteration (but you will be able to uncheck the CheckBox in between iterations), unless...
Keep your existing loop code, but add an inner loop that calls MsgWaitForMultipleObjects() after CreateProcess() succeeds until the spawned process has exited. While waiting, whenever MsgWaitForMultipleObjects() tells you that a new message is waiting, you can pump the message queue and dispatch any messages that are retrieved. This is the least desirable option, but it requires the least amount of changes to existing code.
Questions like this one:
TPL Dataflow, how to forward items to only one specific target block among many linked target blocks?
propose using the DataflowBlock.NullTarget{T} to discard items from a pipeline, e.g.
forwarder.LinkTo(DataflowBlock.NullTarget<SomeType>());
However, if you use NullTarget like this, how do you wait for Completion? Would it not be better to create a discard block:
ITargetBlock<SomeType> discard = DataflowBlock.NullTarget<SomeType>();
forwarder.LinkTo(discard);
and wait for completion on this? i.e.
discard.Completion.Wait()
Or do you not need to wait for completion of a "NullTarget" block, i.e. is it simply throw away and forget?
This isn't documented, but based on my tests, the Completion of a NullTarget will never complete, even after you Complete() or Fault() it.
What this means is that you can't wait on the completion of NullTarget blocks, because the waiting would never end.
The documentation says: "task_group class represents a collection of parallel work which can be waited on or canceled."
1). Do I take it to mean that tasks need to be logically related (but broken down) and that you will ideally need to wait on them elsewhere to collate the results?
IOW, is it possible to use task_group to just schedule asynchronous tasks that basically have no relation to each other (as an analogy: sort of like dumping each iteration of some processing activity in a queue and picking it up for execution by another thread)? Each of them just execute and die away and as a result I wouldn't even have to wait or cancel them.
(I do understand that the task_group dtor will throw an exception if I don't cancel or wait on incomplete tasks. Lets forget that for the moment and only focus on whether I am using it for the right purpose).
This page has an explanation on task groups - not bad.
In a nutshell,
use task groups (the concurrency::task_group class or the concurrency::parallel_invoke algorithm) when you want to decompose parallel work into smaller pieces and then wait for those smaller pieces to complete.
Currently, I call DoEvents in order to check if Button Foo in Form Bar has been clicked. This approach works but it takes too much processing power, delaying the program.
I believe that the delay could be reduced if I could only check if Button Foo has been clicked, instead of all the other forms that DoEvents has to go through.
Any ideas on how can I check if Button Foo was clicked?
VB6 was not really designed for what you seem to be doing (some sort of long-running straight-line code that does not exit back to give the message loop control). Normally such a task would be delegated to a worker thread, and in VB6 this means some external component implemented in C++ most of the time.
There are only a very few kinds of approaches to take to do this for your ad-hoc logic:
Hacks creating separate threads via API calls, not very reliable in VB6 for a number of reasons.
A tricky thread-per-object ActiveX EXE implementing a class to handle your long-running workload.
A separate non-interactive worker process to be run and monitored by your GUI program.
That's pretty much it.
The prescribed method of doing this sort of thing is described in the VB6 documentation. You break your long-running loop up and invert the logic into a repeatable "quantum" of work (like n iterations of your processing loop), and maintain the state of your workload in Form-global data. Then you use a Timer control with its interval set to 1 or 16 (hardly matters, they normally take at least 16ms to trigger) and run your workload quantum within its event handler.
So if you simply had a loop that currently iterates 100,000 times doing something you might break it up so that it runs 500 times for each Timer tick. The quantum size will probably need to be tuned based on what is done within the loop - 500 is just a value chosen for illustration. You'll want to adjust this until it leaves the UI responsive without starving your background workload too much (slowing completion down).
If your code is heavy enough to not call DoEvents or just finish running periodically, then your app won't even know the button has been pressed. The DoEvents call allows windows, and your application to catch up on all notifications.
The correct way to resolve this is a worker thread (see this article on how to do something like this in VB6) but failing that, a periodic DoEvents is required and in turn, some re-entrancy blocking on the call into the long running code.