views:

92

answers:

2
+1  Q: 

C# Synchronization

I have a question about synchronisation:

private void ProcessStuff(Task sometask, Form progressform)
{
    if (sometask.foo == "A")
        DoStuff();  //This one is SYNchronous
    else
    {
        ThirdPartyObject Q = new ThirdPartyObject();
        Q.ProgessChanged += delegate(object sender, ProgressChangedEventArgs e) {
            progressform.ShowProgress(e.ProgressPercentage);
        };
        Q.TaskCompleted += delegate(object sender, TaskResult result) { /* ??? */ };
        Q.Execute("X", "Y", "Z");   //This one executes ASYNchronous
    }
}

DoStuff() executes synchronous (and is a "short running" task, e.g. < 1 sec). The third-party's .Execute method on the other hand executes A-synchronously. I want the method ProcessStuff to be executed synchronously always; so I want it to return when Q.Execute is completed. Q raises the TaskCompleted event when it's done. But I ALSO want to report it's progress.

I can't use a ManualResetEvent because the .WaitOne() method will block the current thread and thus block reporting the progress. The ProcessStuff method gets called for each object in a queue and the tasks in that queue need to be executed in-order, non-parallel.

while (MyQueue.Count > 0)
    ProcessStuff(MyQueue.Dequeue(), MyProgressDialog);

I am, for this project, stuck with .Net 2.0

It's friday night and am tired so I might have overlooked something but I don't see how to fix this. This works; but I don't think it's the way to go:

private void ProcessStuff(Task sometask, Form progressform)
{
    ...
        Q.TaskCompleted += delegate(object sender, TaskResult result) { /* ??? */ };
        Q.Execute("X", "Y", "Z");   //This one executes ASYNchronous
        while (Q.IsBusy) {
            //I Could Thread.Sleep(10) here...
            Application.DoEvents();
        }
    }
}

Can anyone nudge me in the right direction?

A: 

Hi RobIII,

There is no way to do this in one method if I correctly understand your needs. Yes, except

Application.DoEvents();

The main issue that you want use procedure-based approach but you should message-based. I'll try to explain.

You have something like

public partial class MyForm : Form
{
    ProgressBar progress;
    Button startTaskButton;
    void OnClick_startTaskButton();

You want start some time-consuming task in background using Thread/Process/BackgroundWorker or ThreadPool. And you need that Form interact with user and show him task progress during mentioned task is executing.

So you need break your ProgressStaff at least two methods: the first will start task executing and the second will react on task complete event.

//Off top: As I see your ThirdPartyObject class doesn't receive instance of Form so you should syncronize manually.

So your code will looks like this:

void OnClick_startTaskButton()
{
     ProcessStuff(GetTask(), this);
}

private void ProcessStuff(Task sometask, Form progressform)
{
    if (sometask.foo == "A")
        DoStuff();  //This one is SYNchronous
    else
    {
        ThirdPartyObject Q = new ThirdPartyObject();
        Q.ProgessChanged += delegate(object sender, ProgressChangedEventArgs e) 
            { TaskProgessChanged(sender, e); };
        Q.TaskCompleted += delegate(object sender, TaskResult result) 
            { TaskCompleted(sender, result); };
        Q.Execute("X", "Y", "Z");   //This one executes ASYNchronous
    }
}

void TaskProgessChanged(object sender, ProgressChangedEventArgs e)
{
    if (InvokeRequired) Invoke(TaskProgessChanged, new object[] {sender, e} );
    else ShowProgress(e.ProgressPercentage);
}

void TaskCompleted(object sender, TaskResult result)
{
    if (InvokeRequired) Invoke(TaskComplete, new object[] {sender, result} );
    else {
        MessageBox.Show("Task is completed with result :" + result.ToString());
    }
}

======================

Well, if you really want to fell like your ProcessStuff method executes synchronously and in the same time Form reflect progress and you can't divide ProcessStuff into two methods - you may modify my solutions into the following way:

private void ProcessStuff(Task sometask, Form progressform)
{
    ProcessStuff(sometask, progressform, true);
}

private void ProcessStuff(Task sometask, Form progressform, bool isNewTask)
{
    if (isNewTask)
        if (sometask.foo == "A")
            DoStuff();  //This one is SYNchronous
        else
        {
            ThirdPartyObject Q = new ThirdPartyObject();
            Q.ProgessChanged += delegate(object sender, ProgressChangedEventArgs e) {
                progressform.ShowProgress(e.ProgressPercentage);
            };
            Q.TaskCompleted += delegate(object sender, TaskResult result) 
                { ProcessStuff(sometask, this, false); };
            Q.Execute("X", "Y", "Z");   //This one executes ASYNchronous
        }
    else
    {
        if (InvokeRequired) Invoke(TaskComplete, new object[] {sender, result, isNewTask} );
        else {
            //Task is completed
            MessageBox.Show("Task is completed");
        }
    }
}

But imho that will be bad style ;)

(I don't check is this code compiled and suppose you haven't problems with that)

VMykyt
+1  A: 

I've decided to handle it differently;

private Queue<Task> myqueue;

private void Main() {
    //Do stuff
    //Fill queue
    ProcessQueue();        
}
private void ProcessQueue() {
    if (myqeue.count>1)
        ProcessStuff(myqeue.Dequeue());
    else
        MessageBox.Show("Done!");
}
private void ProcessStuff(Task sometask, Form progressform)
{
    if (sometask.foo == "A") {
        DoStuff();  //This one is SYNchronous
        ProcessQueue();
    }
    else
    {
        ThirdPartyObject Q = new ThirdPartyObject();
        Q.ProgessChanged += delegate(object sender, ProgressChangedEventArgs e) {
            progressform.ShowProgress(e.ProgressPercentage);
        };
        Q.TaskCompleted += delegate(object sender, TaskResult result) {
            ProcessQueue();
        };
        Q.Execute("X", "Y", "Z");   //This one executes ASYNchronous
    }
}

This is the easiest fix and I haven't got a clue as to why I didn't see that on friday...

RobIII