Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating BackgroundWorker with Queue

I need to create queue and use it with BackgroundWorker. So I can add operations and when one is done next is starting in background. I found this code by google:

public class QueuedBackgroundWorker<T>
{
    public void QueueWorkItem(
        Queue queue,
        T inputArgument,
        Func<T> doWork,
        Action workerCompleted)
    {
        if (queue == null) throw new ArgumentNullException("queue");

        BackgroundWorker bw = new BackgroundWorker();
        bw.WorkerReportsProgress = false;
        bw.WorkerSupportsCancellation = false;
        bw.DoWork += (sender, args) =>
        {
            if (doWork != null)
            {
                args.Result = doWork(new DoWorkArgument<T>((T)args.Argument));
            }
        };
        bw.RunWorkerCompleted += (sender, args) =>
        {
            if (workerCompleted != null)
            {
                workerCompleted(new WorkerResult<T>((T)args.Result, args.Error));
            }
            queue.Dequeue();
            if (queue.Count > 0)
            {
                QueueItem<T> nextItem = queue.Peek() as QueueItem<T>;
                nextItem.BackgroundWorker.RunWorkerAsync(nextItem.Argument);
            }
        };

        queue.Enqueue(new QueueItem<T>(bw, inputArgument));
        if (queue.Count == 1)
        {
            QueueItem<T> nextItem = queue.Peek() as QueueItem<T>;
            nextItem.BackgroundWorker.RunWorkerAsync(nextItem.Argument);
        }
    }
}

public class DoWorkArgument<T>
{
    public DoWorkArgument(T argument)
    {
        this.Argument = argument;
    }
    public T Argument { get; private set; }
}

public class WorkerResult<T>
{
    public WorkerResult(T result, Exception error)
    {
        this.Result = result;
        this.Error = error;
    }

    public T Result { get; private set; }
    public Exception Error { get; private set; }
}

public class QueueItem<T>
{
    public QueueItem(BackgroundWorker backgroundWorker, T argument)
    {
        this.BackgroundWorker = backgroundWorker;
        this.Argument = argument;
    }

    public T Argument { get; private set; }
    public BackgroundWorker BackgroundWorker { get; private set; }
}

But I have problem with doWork and workerCompleted. I get error:

Delegate 'Func' does not take 1 arguments

How can I fix this? How should I change parameters? Thanks

like image 237
Libor Zapletal Avatar asked Feb 27 '13 18:02

Libor Zapletal


1 Answers

It seems you are missing the second generic parameter - Tout;

The following code should take care of it:

using System;
using System.Collections.Generic;
using System.ComponentModel;

public static class QueuedBackgroundWorker
{
    public static void QueueWorkItem<Tin, Tout>(
        Queue<QueueItem<Tin>> queue,
        Tin inputArgument,
        Func<DoWorkArgument<Tin>, Tout> doWork,
        Action<WorkerResult<Tout>> workerCompleted)
    {
        if (queue == null) throw new ArgumentNullException("queue");

        BackgroundWorker bw = new BackgroundWorker();
        bw.WorkerReportsProgress = false;
        bw.WorkerSupportsCancellation = false;
        bw.DoWork += (sender, args) =>
            {
                if (doWork != null)
                {
                    args.Result = doWork(new DoWorkArgument<Tin>((Tin)args.Argument));
                }
            };
        bw.RunWorkerCompleted += (sender, args) =>
            {
                if (workerCompleted != null)
                {
                    workerCompleted(new WorkerResult<Tout>((Tout)args.Result, args.Error));
                }
                queue.Dequeue();
                if (queue.Count > 0)
                {
                    QueueItem<Tin> nextItem = queue.Peek(); // as QueueItem<T>;
                    nextItem.BackgroundWorker.RunWorkerAsync(nextItem.Argument);
                }
            };

        queue.Enqueue(new QueueItem<Tin>(bw, inputArgument));
        if (queue.Count == 1)
        {
            QueueItem<Tin> nextItem = queue.Peek() as QueueItem<Tin>;
            nextItem.BackgroundWorker.RunWorkerAsync(nextItem.Argument);
        }
    }
}

public class DoWorkArgument<T>
{
    public DoWorkArgument(T argument)
    {
        this.Argument = argument;
    }

    public T Argument { get; private set; }
}

public class WorkerResult<T>
{
    public WorkerResult(T result, Exception error)
    {
        this.Result = result;
        this.Error = error;
    }

    public T Result { get; private set; }

    public Exception Error { get; private set; }
}

public class QueueItem<T>
{
    public QueueItem(BackgroundWorker backgroundWorker, T argument)
    {
        this.BackgroundWorker = backgroundWorker;
        this.Argument = argument;
    }

    public T Argument { get; private set; }

    public BackgroundWorker BackgroundWorker { get; private set; }
}

And the usage should be:

    private readonly Queue<QueueItem<int>> _workerQueue = new Queue<QueueItem<int>>();
    private int _workerId = 1;

    [Test]
    public void BackgroundTest()
    {
        QueuedBackgroundWorker.QueueWorkItem(
            this._workerQueue, 
            this._workerId++,
            args =>  // DoWork
                {
                    var currentTaskId = args.Argument;
                    var now = DateTime.Now.ToLongTimeString();
                    var message = string.Format("DoWork thread started at '{0}': Task Number={1}", now, currentTaskId);
                    return new { WorkerId = currentTaskId, Message = message };
                },
            args =>  // RunWorkerCompleted
                {
                    var currentWorkerId = args.Result.WorkerId;
                    var msg = args.Result.Message;

                    var now  = DateTime.Now.ToShortTimeString();
                    var completeMessage = string.Format(
                        "RunWorkerCompleted completed at '{0}'; for Task Number={1}, DoWork Message={2}",
                        now,
                        currentWorkerId,
                        msg);
                }
            );
    }
like image 188
Aaron Avatar answered Oct 01 '22 18:10

Aaron