c# - 任务同步的正确方法?

标签 c# synchronization task

我正在做的事情是否是完成此任务的正确/最佳方法?

我有一个带计时器的窗口。每次计时器计时时,我都会调用如下所示的 RunTask 方法。在 RunTask 中,我调用了 DoTheThingDoTheThing 可能需要一段时间才能运行,并且可能会失败(这是数据库更新)。我想确保在任何时间点,我只有一个 DoTheThing 未完成。我还想确保我没有一堆 RunTask 实例都排队等待正在运行的 RunTask 实例释放锁 做事

public void RunTask()
{
    bool canRunTask = true;

    // Check if another instance of this method is currently executing.  If so, do not execute the rest of this method
    lock (this.runTaskLock)
    {
        if (this.isTaskRunning)
        {
            canRunTask = false;
        }
        else
        {
            this.isTaskRunning = true;
        }
    }

    // Call DoTheThing if another instance is not currently outstanding
    if (canRunTask)
    {
        try
        {
            Task task = new Task(() => DoTheThing());
            task.Start();
        }
        catch (Exception ex)
        {
            // Handle the exception
        }
        finally
        {
            lock (this.runTaskLock)
            {
                this.isTaskRunning = false;
            }
        }
    }
}

由于程序的架构,我宁愿将我所有的线程同步放在这个方法中,而不是启用和禁用计时器。

最佳答案

通过略微不同地思考问题,事情变得容易多了。而不是每隔 x 触发一个计时器秒,为什么不等x调用之间的秒数?

现在您可以运行一个异步循环来完成计划的工作,并为您自己省去一大堆痛苦的同步工作。

async Task RunActionPeriodicallyAsync(Action action, 
                           TimeSpan ts, 
                           CancellationToken token = default(CancellationToken))
{
    while(!token.IsCancellationRequested)
    {
        action();
        await Task.Delay(ts, token);
        //or alternatively (see comment below)
        //var delayTask = Task.Delay(ts, token);
        //action();
        //await delayTask;
    }
}

现在,只需调用 RunActionPeriodicallyAsync一次,并且对其操作的调用永远不会重叠。

RunActionPeriodicallyAsync(() => DoSomething(), TimeSpan.FromSeconds(10))

您可以重载它以采取异步“操作”...实际上是一个 Func<Task> ...

async Task RunActionPeriodicallyAsync(Func<CancellationToken, Task> actionAsync, 
                           TimeSpan ts, 
                           CancellationToken token = default(CancellationToken))
{
    while(!token.IsCancellationRequested)
    {
        await actionAsync(token);
        await Task.Delay(ts, token);
        //or alternatively (see comment below)
        //await Task.WhenAll(actionAsync(token), Task.Delay(ts, token))
    }
}

并使用它:

RunActionPeriodicallyAsync(async cancTok => await DoSomethingAsync(cancTok), 
                           TimeSpan.FromSeconds(10))

关于c# - 任务同步的正确方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35157709/

相关文章:

c# - 在 MVVM 中显示对话框并设置对话框选项

synchronization - Rebus - 发送命令并等待处理程序

JavaFX : How can I use correctly a ProgressIndicator in JavaFX

android - ActivityManager.killBackgroundProcesses 不同于 "Force stop"

c# - ICommand MVVM 实现

c# - 在我的 C# 应用程序中延迟加载

c# - 为什么我们使用 ref 参数得到 ArrayTypeMismatch?

mysql - mysql中同步存储过程执行

c++ - 宽松的原子计数器安全吗?

c# - 挂断异步 TCP 客户端连接