Синхронизация C # - PullRequest
       7

Синхронизация C #

1 голос
/ 16 июля 2010

У меня есть вопрос по поводу синхронизации:

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 () выполняет синхронно (и является «кратковременной» задачей, например, <1 сек).С другой стороны, метод .Execute стороннего разработчика выполняется A-синхронно.Я хочу, чтобы метод ProcessStuff всегда выполнялся синхронно;поэтому я хочу, чтобы он вернулся, когда Q.Execute завершен.Q вызывает событие TaskCompleted по завершении.Но я также хочу сообщить о его прогрессе. </p>

Я не могу использовать ManualResetEvent, потому что метод .WaitOne() заблокирует текущий поток и, таким образом, заблокирует сообщение о прогрессе.Метод ProcessStuff вызывается для каждого объекта в очереди, и задачи в этой очереди должны выполняться не по порядку, а параллельно.

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

Я для этого проекта застрял в .Net 2.0

Сегодня пятница, и я устала, поэтому я могла что-то упустить из виду, но я не вижу, как это исправить.Это работает;но я не думаю, что это путь:

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();
        }
    }
}

Кто-нибудь может подтолкнуть меня в правильном направлении?

Ответы [ 2 ]

1 голос
/ 19 июля 2010

Я решил обращаться с этим по-другому;

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
    }
}

Это самое простое исправление, и я понятия не имею, почему я не видел этого в пятницу ...

0 голосов
/ 19 июля 2010

Невозможно сделать это одним способом, если я правильно понимаю ваши потребности.Да, за исключением

Application.DoEvents();

Основная проблема, которую вы хотите использовать на основе процедур, но вы должны основываться на сообщениях.Я попытаюсь объяснить.

У вас есть что-то вроде

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

Вы хотите запустить некоторую трудоемкую задачу в фоновом режиме, используя Thread / Process / BackgroundWorker или ThreadPool.И вам нужно, чтобы Форма взаимодействовала с пользователем и показывала ему ход выполнения задачи во время выполнения указанной задачи.

Таким образом, вам нужно прервать ваш ProgressStaff по крайней мере двумя способами: первый запустит выполнение задачи, а второй отреагирует на ее выполнение.event.

// Off top: как я вижу, ваш класс ThirdPartyObject не получает экземпляр Form, поэтому вы должны синхронизироваться вручную.

Таким образом, ваш код будет выглядеть следующим образом:

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());
    }
}

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

Хорошо, если вы действительно хотите упасть, как ваш ProcessStuffметод выполняется синхронно и в то же время форма отражает прогресс, и вы не можете разделить ProcessStuff на два метода - вы можете изменить мои решения следующим образом:

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");
        }
    }
}

Но imho, это будет плохим стилем;)

(я не проверяю, скомпилирован ли этот код, и предположим, что с этим у вас нет проблем)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...