Do I have to check the InvokeRequired and use the Invoke function with every control I want to update? - vb.net

I'm writing a scheduler. It has a single form frmMain, which shows jobs that are currently running, and a history of job steps that have run. It has an object of class Scheduler that manages running new jobs. Scheduler keeps a collection class, List which contains objects of class RunningJob. RunningJob executes each step in turn through a series of sub-classes.
When a job is started, the Scheduler creates a new BackgroundWorker with the DoWork, ProgressChanged and RunWorkerCompleted methods setup with handlers that point back into the instance of RunningJob.
Each time a job/step starts/ends, one of these handers in RunningJob raises an appropriate event into Scheduler and Scheduler raises an appropriate event into frmMain. i.e.:
frmMain (1 instance) <---- Scheduler (1 instance) <---- RunningJob.WorkerProgressChanged (many instances)
The RunningJob executes correctly, but the reporting going up to the interface is not working correctly. Also any logging to files I do is suspect (I'm using a single function: LogInfo to do this). I have a number of questions:
When I use InvokeRequired() and Invoke() within frmMain, do I have to do this with every single control I want to update (there are several). Can I just check InvokeRequired() on one control and use Invoke on all of them based on that result.
Why bother checking InvokeRequired() at all and just use Invoke() every single time? It will make for simpler code.
There is only one instance of Scheduler and I am raising events to get execution back into it from each Job. I think this is part of the problem. How is multithreading handled doing this? Is there some sort of InvokeRequired/Invoke check I can do on the events before raising them? Can I raise events at all in this situation? I like events, rather than calling methods on the owner class, because it improves encapsulation. What is best practice here?
In general, if I'm calling a piece of code from many different threads, not necessarily to update a form, but just to perform some function (e.g. add a line of text to a file for logging purposes), how do I block one thread until the other has completed?

Related

Triggering non-interrupting boundary event with variables

My question is about the Camunda API method RuntimeService#messageEventReceived(java.lang.String, java.lang.String, java.util.Map<java.lang.String,java.lang.Object>). We use this method to trigger a non-interrupting boundary message event (on a receive task that is waiting for a different message), like this. As third parameter in the method call, we are passing some process variables.
As expected, this leaves the receive task active and starts a new execution leaving the boundary event. I would have expected that the process variables passed to the third argument of RuntimeService#messageEventReceived would now be stored in the newly created execution, but it seems to be the case that they are stored in the execution of the receive task. This does not make much sense to me, because this is not the execution that "resulted" from the message.
We can workaround this problem by determining which execution is new after the execution of RuntimeService#messageEventReceived and attaching process variables there manually. But this does not seem very elegant - does anyone know a better solution? Or am I misunderstanding something?
This is expected behavior, see the java doc of the method
void messageEventReceived(String, String, Map)
void messageEventReceived(String messageName,
String executionId,
Map<String,Object> processVariables)
Notifies the process engine that a message event with the name 'messageName' has been received and has been correlated to an execution with id 'executionId'. The waiting execution is notified synchronously. Note that you need to provide the exact execution that is waiting for the message if the process instance contains multiple executions.
Parameters:
messageName - the name of the message event
executionId - the id of the process instance or the execution to deliver the message to
processVariables - a map of variables added to the execution
Since the process variables are set on the existing execution they are also available on the new created child execution.
As alternative you could create a ServiceTask after the Boundary event, which creates the process variables OR you create another ReceiveTask after the Boundary event. This receive task could be completed with your message and the needed variables.

Project Job Scheduling: Where are resetPanel and createChart called?

I am working on a Class that takes data from a csv, works with a Scheduler Object, and associates the data with the scheduler's attributes(Project, Job, Allocation, Resource, etc). I was thinking after I got everything down(ProjectList, JobList, AllocationList, ExecutionModeList, Resources) I could just pass the scheduler object into createChart.
However, I am still unsure as to where resetPanel and createChart are called( I understand that the ProjectJobPanel has these functions).
So my 2 questions are:
Where are these functions called?( I couldn't find this information in the documentation)
If i want to display my data, do I need to do anything else other than pass in the scheduler object into the "createChart" function?
resetPanel() is called by the example swing dialog when a new dataset is loaded. If updatePanel() isn't overwritten, it's also called when a new best solution is found (so for every best solution changed event).

How make a Sub to Address a [New Thread] Call?

I have a BackgroundWorker routine that performs a lot of things and call ThreadSafe functions to update UI controls. In some points of that routine I call some subroutines to write log information into a SQL table, using the Parallel Library to make them in another Thread. It´s functioning like a charm.
The threaded LOG calls are like this, where Log_Compressed_File() is a subroutine:
Dim Log_Threaded as Thread = New Thread(Sub() Log_Compressed_File(Username, UserAreaCode, Filename))
Log_Threaded.IsBackground = False
Log_Threaded.Priority = ThreadPriority.Highest
Log_Threaded.SetApartmentState(Threading.ApartmentState.MTA)
Log_Threaded.Start
As shown above, each log call is made using 5 lines of code, defining the new thread itself and some important parameters.
My questions are:
1) can I produce a Sub to address these calls, trying to reduce the lines of the main routine?
Just to make it clear: I have more than 35 LOG calls within the main routine and, if each one would utilize 5 lines of code, I will have 175 lines, when I could have only the original 35 calls to a new subroutine that could address the new thread.
2) Can I call that subroutine from within the BackgroundWorker without to call a delegate function (ThreadSafe) like I use in UI updates?
The function like shown above can be performed within the BackgroundWorker without to a DELEGATE function (the LOG_COMPRESSED_FILE is a normal Sub, not a Delegate call).
Thanks in advance for any help!
Yes. Just write a method with the same three parameters as your Log_Compressed_File method and then put that code into that method.
Yes. Do you understand why you need to use a delegate at all? The point is that you cannot access the Handle of a control on any thread other than the one it was created on. Invoking a delegate ensures that code accessing the control's Handle is executed on the correct thread. If you're not accessing a control then there's no Handle so why would it matter what thread you execute the code on?

Suitable pattern for updating a progress bar from multiple threads (using TPL?)

I've been busy updating my brain with the TPL because I intend on using it for my new application (which uses .Net Framework 4.0). However I have some doubts that someone might clarify for me. Previously, I had a progress form which I would launch from the main (GUI) thread after I started the thread which needed to display its' progress. It looked something like this:
sortThread = New Thread(AddressOf _Sorter.Sort())
_ProgressForm = New FrmProgress()
_Sorter.ProgressForm = _ProgressForm
sortThread.Start()
progressForm.ShowDialog()
Basically it would initialize the thread, initialize a FrmProgress form object and assign it to the Sorter object which would then update the progress form (which contained a progress bar and some labels) from its Sort() sub on the separate thread. Updating these control properties was achieved by checking the InvokeRequired property of the FrmProgress form and if needed it would then use the Invoke() method of the control that was to be updated... ex:
Public Sub IncrementProgressBar(x As Integer)
If Me.InvokeRequired Then
pb_MainProgressBar.Invoke(Sub() IncrementProgressBar(x))
Else
pb_MainProgressBar.Increment(x)
End If
End Sub
Now I am interested in using TPL to launch separate worker threads (multiple) that may want to update the progress bar. Should I use the same pattern or should I consider accessing a public TaskScheduler.FromCurrentSynchronizationContext context that was obtained in the main GUI thread? In both cases I suppose I should provide some kind of locking mechanism on the form (SyncLock?)
Invoke should be sufficient, as you are doing. If two different threads try to invoke in parallel the first one will execute first, then the second when the UI thread becomes free. The UI thread cannot service two invokes simultaneously - they are naturally handled in FIFO sequence so there is no issue with thread safety. Any number of threads can invoke on the main thread without worrying about each other or using any additional locking mechanism.
Note, however, that any thread calling Invoke will block until the main thread can service the call. If you, for example, had many threads invoking heavy code at the same time then your various threads would block on the invoke calls until they got their kick at the can, so to speak. If you use BeginInvoke then the calling thread will simply continue executing and the invoked method will be placed in the UI thread's queue (which it will service as soon as it can).

Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on

I am writing a filewatcher windows application which will look for changes in a specified folder and then logs the details in a txt file.
I followed exactly what is mentioned in this article below
http://www.codeproject.com/KB/dotnet/folderwatcher.aspx
When I hit F5 from my application and then create or modify a file in the folder that is being watched it throws the below mentioned error.
Please help
Cross-thread operation not valid: Control 'txtFolderActivity' accessed from a thread other than the thread it was created on.
You have to use the Invoke method on the form e.g. with an anonymous delegate to make your changes in reaction to the event.
The event handler is raised with another thread. This 2nd thread cannot access controls in your form. It has to "Invoke" them to let the thread do all control work that initially created them.
Instead of:
myForm.Control1.Text = "newText";
you have to write:
myForm.Invoke(new Action(
delegate()
{
myForm.Control1.Text = "newText";
}));
You are trying to update the UI from a non-UI thread. UI has a thread affinity and can only be updated from a thread that created it. If you're using WinForms, check out How to: make thread-safe calls to Windows Forms Controls MSDN article. Basically you will need to update the UI via Control.Invoke method. For WPF, you need to use DispatcherObject.
Basically you must have two threads in your application, at least, and the thread that your control logic is on is different, so you get this error, as the controls are not threadsafe.
This is to protect you from problems that could be caused by multiple threads changing the same control at the same time.
You can find considerably more detail by looking here:
http://msdn.microsoft.com/en-us/library/ms171728%28VS.80%29.aspx