简体   繁体   中英

How to monitor and stop running tasks separately using tpl

I am new to parallel programming and tpl in c# and I am doing the following test in order to see how tasks work. Each time I click the button1 and the bounded method is fired, a new task will start. When I click button_2 all tasks will exit the loop and I will get the time elapsed for all tasks and there task id.

So is there a way to monitor these tasks while they are working in a task pool so I can stop them if I wish separately using the Task Id?

        Boolean stopprogramm = false;
        private void button1_Click(object sender, EventArgs e)
        {

            Task timerTask1 = Task.Factory.StartNew(() =>
                {
                    Stopwatch watch = new Stopwatch();
                    watch.Start();
                    while (stopprogramm == false)
                    {
                        //Do some work
                    }
                    Console.WriteLine("time ellapsed for No partitioning at all version {0}ms , thread id was {1}", watch.ElapsedMilliseconds, Task.CurrentId);
                    watch.Stop();

                });


        }
        private void button2_Click(object sender, EventArgs e)
        {
            stopprogramm = true;
        }

Something like this could work.

    private Dictionary<Guid, TaskTracker> _taskMap = new Dictionary<Guid, TaskTracker>();

    private void OnButton1Click(object sender, EventArgs eventArgs)
    {
        TaskTracker taskTracker = new TaskTracker(Guid.NewGuid(), OnDoWork);
        _taskMap.Add(taskTracker.Identity, taskTracker);
        taskTracker.Run();
    }

    private void OnDoWork()
    {
        // Do some work
    }

    private void OnButton2Click(object sender, EventArgs eventArgs)
    {
        Guid identity = _taskMap.Count > 0 ? _taskMap.First().Value.Identity : default(Guid);  // find some way to get the desired task

        TaskTracker taskTracker;
        if (_taskMap.TryGetValue(identity, out taskTracker))
        {
            taskTracker.TaskExiting += OnTaskExiting;
            taskTracker.Stop();
        }
    }

    private void OnTaskExiting(object sender, EventArgs eventArgs)
    {
        TaskTracker taskTracker = (TaskTracker)sender;
        taskTracker.TaskExiting -= OnTaskExiting;
        _taskMap.Remove(taskTracker.Identity);
        // do what you want with the timings
    }

The class for task is this:

public class TaskTracker
{
    private readonly Action OnDoWork;
    private Task _task;
    private bool _isRunning = true;

    public TaskTracker(Guid identity, Action onDoWork)
    {
        Identity = identity;
        OnDoWork = onDoWork;
    }

    public readonly Guid Identity;
    public readonly Stopwatch Stopwatch = new Stopwatch();

    public event EventHandler TaskExiting;

    public void Run()
    {
        Task _task = Task.Factory.StartNew(
            () =>
                {
                    Stopwatch.Start();
                    try
                    {
                        while (_isRunning)
                        {
                            OnDoWork();
                        }
                        if (TaskExiting != null)
                        {
                            TaskExiting(this, EventArgs.Empty);
                        }
                    }
                    finally
                    {
                        Stopwatch.Stop();
                    }
                }
            );
    }

    public void Stop()
    {
        _isRunning = false;
        // wait for task to exit?
        _task = null;
    }
}

You will need to fill in the blanks, meaning tracking tasks and getting the target task when hitting button 2.

You mentioned in one of the comments from my other answer a link, it looks like that link describes how to make it cancellable. I have adapted my example to support this:

    private Dictionary<Guid, TaskTracker> _taskMap = new Dictionary<Guid, TaskTracker>();

    private void OnButton1Click(object sender, EventArgs eventArgs)
    {
        TaskTracker taskTracker = new TaskTracker(Guid.NewGuid(), OnDoWork);
        _taskMap.Add(taskTracker.Identity, taskTracker);
        taskTracker.Start();
    }

    private void OnDoWork(CancellationToken token)
    {
        for (int i = 0; i < 100; i++)
        {
            Thread.Sleep(100); // Do some work, checking if cancel requested every once in a while
            if (token.IsCancellationRequested)
            {
                token.ThrowIfCancellationRequested();
            }
        }
    }

    private void OnButton2Click(object sender, EventArgs eventArgs)
    {
        Guid identity = _taskMap.Count > 0 ? _taskMap.First().Value.Identity : default(Guid);  // find some way to get the desired task

        TaskTracker taskTracker;
        if (_taskMap.TryGetValue(identity, out taskTracker))
        {
            taskTracker.TaskExiting += OnTaskExiting;
            taskTracker.Stop();
        }
    }

    private void OnTaskExiting(object sender, EventArgs eventArgs)
    {
        TaskTracker taskTracker = (TaskTracker)sender;
        taskTracker.TaskExiting -= OnTaskExiting;
        _taskMap.Remove(taskTracker.Identity);

        Console.WriteLine("Time ellapsed for No partitioning at all version {0}ms , thread id was {1}", taskTracker.Stopwatch.ElapsedMilliseconds, Task.CurrentId);
    }

    private void OnButton3Click(object sender, EventArgs eventArgs)
    {
        Guid identity = _taskMap.Count > 0 ? _taskMap.First().Value.Identity : default(Guid);  // find some way to get the desired task

        TaskTracker taskTracker;
        if (_taskMap.TryGetValue(identity, out taskTracker))
        {
            taskTracker.TaskExiting += OnTaskExiting;
            taskTracker.Cancel();
        }
    }

And here is the TaskTracker class:

public class TaskTracker
{
    private readonly Action<CancellationToken> OnDoWork;
    private readonly CancellationTokenSource TokenSource;
    private readonly CancellationToken Token;

    private bool _isRunning;
    private Task _task;

    public TaskTracker(Guid identity, Action<CancellationToken> onDoWork)
    {
        TokenSource = new CancellationTokenSource();
        Token = TokenSource.Token;

        Identity = identity;
        OnDoWork = onDoWork;
    }

    public readonly Guid Identity;
    public readonly Stopwatch Stopwatch = new Stopwatch();

    public event EventHandler TaskExiting;

    public void Start()
    {
        _isRunning = true;
        _task = Task.Factory.StartNew(
            () =>
                {
                    Stopwatch.Start();
                    try
                    {
                        while (_isRunning)
                        {
                            OnDoWork(Token);
                        }
                    }
                    finally
                    {
                        Stopwatch.Stop();

                        if (TaskExiting != null)
                        {
                            TaskExiting(this, EventArgs.Empty);
                        }
                    }
                }, Token
            );
    }

    public void Stop(bool waitForTaskToExit = false)
    {
        if (_task == null)
        {
            throw new InvalidOperationException("Task hasn't been started yet");
        }

        _isRunning = false;
        if (waitForTaskToExit)
        {
            _task.Wait();
        }
        _task = null;
    }

    public void Cancel()
    {
        if (_task == null)
        {
            throw new InvalidOperationException("Task hasn't been started yet");
        }

        _isRunning = false;
        TokenSource.Cancel();
        _task = null;
    }
}

Basically, in your "Worker" you would check to see if the token indicates it is being cancelled, if so do some cleanup and then call the method ThrowIfCancellationRequested on token to break out.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM