0

私はc#での並列プログラミングとtplに不慣れであり、タスクがどのように機能するかを確認するために次のテストを行っています。button1をクリックして、boundedメソッドが起動されるたびに、新しいタスクが開始されます。button_2をクリックすると、すべてのタスクがループを終了し、すべてのタスクの経過時間が取得され、タスクIDが表示されます。

では、タスクプールで作業しているときにこれらのタスクを監視して、タスク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;
        }
4

2 に答える 2

1

このようなものが機能する可能性があります。

    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
    }

タスクのクラスは次のとおりです。

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

ボタン2を押すと、タスクを追跡し、ターゲットタスクを取得することを意味する空白を埋める必要があります。

于 2012-12-02T03:59:40.003 に答える
1

私の他の回答からのコメントの1つにリンクについて言及されましたが、そのリンクはキャンセル可能にする方法を説明しているようです。私はこれをサポートするために私の例を適応させました:

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

そして、これがTaskTrackerクラスです。

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

基本的に、「ワーカー」では、トークンがキャンセルされていることを示しているかどうかを確認します。キャンセルされている場合は、クリーンアップを実行してから、トークンに対してメソッドThrowIfCancellationRequestedを呼び出してブレークアウトします。

于 2012-12-02T06:00:44.877 に答える