Synchronize streams - no user interface

I am trying to write multi-threaded code and run into some synchronization issues. I know there are a lot of posts, but I could not find anything suitable.

I have a System.Timers.Timer that expires every 30 seconds, it goes into db and checks if there are any new jobs. If he finds one, he will complete the task in the current thread (the timer will open a new thread for each passed one). While the work is in progress, I need to inform the main thread (where is the timer) about the progress.

Notes:

  • I do not have an interface, so I can not do beginInvoke (or use a background thread), as I usually do in winforms.
  • I was thinking of implementing ISynchronizeInvoke in my main class, but that seems a bit redundant (maybe I'm wrong here).
  • I have an event in my job class and in its main class, and I fire the event whenever I need, but I worry that it might cause a lock.
  • Each task can take up to 20 minutes.
  • I can have up to 20 tasks performed simultaneously.

My question is:

What is the correct way to notify my main thread of any progress in my work?

Thanks for any help.

+6
multithreading synchronization c #
source share
4 answers

You can also use lock to implement the thread-safe JobManager class, which tracks progress against different workflows. In this example, I just support counting active workflows, but it can be extended to your progress reporting needs.

 class JobManager { private object synchObject = new object(); private int _ActiveJobCount; public int ActiveJobsCount { get { lock (this.synchObject) { return _ActiveJobCount; } } set { lock (this.synchObject) { _ActiveJobCount = value; } } } public void Start(Action job) { var timer = new System.Timers.Timer(1000); timer.Elapsed += (sender, e) => { this.ActiveJobsCount++; job(); this.ActiveJobsCount--; }; timer.Start(); } } 

Example:

 class Program { public static void Main(string[] args) { var manager = new JobManager(); manager.Start(() => Thread.Sleep(3500)); while (true) { Console.WriteLine(manager.ActiveJobsCount); Thread.Sleep(250); } } } 
+2
source share

Use events. For example, the BackgroundWorker class is designed specifically for what you mean.

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

The ReportProgress function ReportProgress along with the ProgressChanged event, is what you will use to update progress.

 pullJobTimer.Elapsed += (sender,e) => { BackgroundWorker worker = new BackgroundWorker(); worker.WorkerReportsProgress = true; worker.DoWork += (s,e) => { // Whatever tasks you want to do // worker.ReportProgress(percentComplete); }; worker.ProgressChanged += mainThread.ProgressChangedEventHandler; worker.RunWorkerAsync(); }; 
+1
source share

You can notify the main thread of progress using the callback method. I.e:

 // in the main thread public void ProgressCallback(int jobNumber, int status) { // handle notification } 

You can pass this callback method to the workflow when it is called (that is, as a delegate), or the workflow code may "know" about it implicitly. In any case, it works.

The jobNumber and status parameters are just examples. You might want you to use a different way of defining tasks to be performed, and you can use the listed type for status. However, you do this, remember that ProgressCallback will be called by several threads at the same time, so if you update any general data structures or write registration information, you will have to protect these resources with locks or other synchronization methods.

You can also use events to do this, but keeping the subscription to the main thread up to date can be a potential problem. You also have the potential of a memory leak if you forget to unsubscribe from the main thread from certain workflow events. Although events will certainly work, I would recommend a callback for this application.

+1
source share

If you don't mind depending on .NET 3.0, you can use Dispatcher to sort requests between threads. It behaves similarly to Control.Invoke () in Windows Forms, but has no Forms dependency. You will need to add a link to the WindowsBase assembly, though (part of .NET 3.0 and newer is the basis for WPF)

If you cannot depend on .NET 3.0, I would say that from the very beginning you have chosen the right solution: Add ISynchronizeInvoke in your main class and pass this timer SynchronizingObject property. Then your timer callback will be called in the main thread, which can then call BackgroundWorkers , which checks the database and starts any jobs in the queue. Jobs will report progress through the ProgressChanged event, which automatically transfers the call to the main thread.

A quick Google search showed this example on how to actually implement the ISynchronizeInvoke interface.

+1
source share

All Articles