DubMan
DubMan

Reputation: 460

Communicate with object inside a Task

I want to know how or even if its required in my case to communicate with an object running inside a Task.

I have a collection of processes, which are generic objects that perform some long running monitoring and calculating:

private IEnumerable<IService> _services;

Since they are based on a common interface they implement a method to "doSomeWork". So for arguments sakes lets call that method DoWork.

I want these methods all to run in a separate task space and not block sequentially, so I am spinning up a task list at a similar scope level to run this part of the program.

private List<Task> ProcessTask = new List<Task>();
private CancellationTokenSource tokenSource = new CancellationTokenSource();
private CancellationToken token;

private void startAll()
{
    token = tokenSource.Token;
    ProcessTask = _services.Select(service => Task.Factory.StartNew(
    () => StartService(service),
    token, 
    TaskCreationOptions.LongRunning,
    TaskScheduler.Current)).ToList();
}

The startservice method basically starts the monitoring and work on the individual item:

private void StartService(IService plugin)
{
   ...
   ...
   plugin.DoWork();
   ...
   ...
}

The services also have a method to "stop" and "continue", which leads to my question. In the heart of using tasks would I be best trying to find a way of influencing the service from withing the task using an event or delegate and pausing/stopping the task or just calling these methods on the item from the external _services collection?

e.g.:

_services.ForEach(item => item.Stop());

If it is the former then how do I raise an event inside the task from out side, or should I monitor an external flag?

Upvotes: 3

Views: 659

Answers (2)

DubMan
DubMan

Reputation: 460

Complete solution code is: My new container class

internal class ServiceContainer
{
    /// <summary>
    /// Process service which runs the monitor
    /// </summary>
    public IService ServiceProcess { get; private set; }

    /// <summary>
    /// Cancellation token used to cancel the operation
    /// </summary>
    public CancellationTokenSource CancelTokenSource { get; private set; }

    internal ProcessContainer(IService plugin)
    {
        this.PluginProcess = plugin;
        CancelTokenSource = new CancellationTokenSource();
    }
}

Then create a list of service wrappers:

serviceWrapperList = _plugins.Select(service => new ServiceContainer(service)).ToList();

Then I get my task running and based service set:

ProcessTaskList = serviceWrapperList.Select(serviceSet => Task.Factory.StartNew(
            () =>
            {
                IService service = serviceSet.ServiceProcess;
                CancellationToken token = serviceSet.CancelTokenSource.Token;
                StartService(service);
                token.Register(() => StopPlugin(service));
            },
            serviceSet.CancelTokenSource.Token,
            TaskCreationOptions.LongRunning,
            TaskScheduler.Current)).ToList();

Finally I have my stop all method.

    protected void StopAllServices()
    {
        ProcessTaskList.ForEach(f => f.CancelTokenSource.Cancel());
    }

Upvotes: 0

usr
usr

Reputation: 171178

You can use the CancellationToken as a one-shot event:

token.Register(() => item.Stop())

Hopefully, this will work with your particular "service" API. Note, that the token can fire before the service starts and also after you are done.

Upvotes: 2

Related Questions