如何共享多命令模式不同的线程在C#中同样的背景下? [英] How to share the same context with different threads in multi-Command Pattern in C#?

查看:91
本文介绍了如何共享多命令模式不同的线程在C#中同样的背景下?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有是一个扩展的实施命令模式,以支持在C#中的多指令(组):

There is an extended implementation of command pattern to support multi-commands (groups) in C#:

var ctx= //the context object I am sharing...

var commandGroup1 = new MultiItemCommand(ctx, new List<ICommand>
    {
        new Command1(ctx),
        new Command2(ctx)
    });

var commandGroup2 = new MultiItemCommand(ctx, new List<ICommand>
    {
        new Command3(ctx),
        new Command4(ctx)
    });

var groups = new MultiCommand(new List<ICommand>
    {   
        commandGroup1 ,
        commandGroup2 
    }, null);

现在,执行是这样的:

groups.Execute();



我共享相同的背景(CTX)对象。

在Web应用程序的执行计划需要分开
commandGroup1 commandGroup2 在不同的线程组。具体而言, commandGroup2 将在主线程一个新的线程和 commandGroup1 执行。

The execution plan of the web app needs to separate commandGroup1 and commandGroup2 groups in different thread. In specific, commandGroup2 will be executed in a new thread and commandGroup1 in the main thread.

执行现在看起来像:

//In Main Thread
commandGroup1.Execute();

//In the new Thread
commandGroup2.Execute();

如何线程安全共享同一个上下文对象(CTX),以便能够回滚 commandGroup1 由新主题?

How can I thread-safely share the same context object (ctx), so as to be able to rollback the commandGroup1 from the new Thread ?

t.Start(CTX); 足够或做我必须使用锁或东西。

Is t.Start(ctx); enough or do I have to use lock or something?

某些代码执行的例子是这里

Some code implementation example is here

推荐答案

假设我们有一个聚合在某些时候必须异步执行的所有命令的个ICommand和列表的MultiCommand类。所有命令必须共享环境。每个命令可以改变环境状态,但没有设置命令!

Assume we have a MultiCommand class that aggregates a list of ICommands and at some time must execute all commands Asynchronously. All Commands must share context. Each command could change context state, but there is no set order!

第一步是踢了所有的ICommand执行传入CTX方法。下一步是建立新的CTX更改事件侦听器。

The first step is to kick off all ICommand Execute methods passing in the CTX. The next step is to set up an event listener for new CTX Changes.

public class MultiCommand
{
    private System.Collections.Generic.List<ICommand> list;
    public List<ICommand> Commands { get { return list; } }
    public CommandContext SharedContext { get; set; }


    public MultiCommand() { }
    public MultiCommand(System.Collections.Generic.List<ICommand> list)
    {
        this.list = list;
        //Hook up listener for new Command CTX from other tasks
        XEvents.CommandCTX += OnCommandCTX;
    }

    private void OnCommandCTX(object sender, CommandContext e)
    {
        //Some other task finished, update SharedContext
        SharedContext = e;
    }

    public MultiCommand Add(ICommand cc)
    {
        list.Add(cc);
        return this;
    }

    internal void Execute()
    {
        list.ForEach(cmd =>
        {
            cmd.Execute(SharedContext);
        });
    }
    public static MultiCommand New()
    {
        return new MultiCommand();
    }
}

每个命令处理类似这样的异步部分:

Each command handles the asynchronous part similar to this:

internal class Command1 : ICommand
{

    public event EventHandler CanExecuteChanged;

    public bool CanExecute(object parameter)
    {
        throw new NotImplementedException();
    }

    public async void Execute(object parameter)
    {
        var ctx = (CommandContext)parameter;
        var newCTX =   await Task<CommandContext>.Run(() => {
            //the command context is here running in it's own independent Task
            //Any changes here are only known here, unless we return the changes using a 'closure'
            //the closure is this code - var newCTX = await Task<CommandContext>Run
            //newCTX is said to be 'closing' over the task results
            ctx.Data = GetNewData();
            return ctx;
        });
        newCTX.NotifyNewCommmandContext();

    }

    private RequiredData GetNewData()
    {
        throw new NotImplementedException();
    }
}



最后,我们建立了一个共同的事件处理程序,并通知系统

Finally we set up a common event handler and notification system.

public static class XEvents
{
    public static EventHandler<CommandContext> CommandCTX { get; set; }
    public static void NotifyNewCommmandContext(this CommandContext ctx, [CallerMemberName] string caller = "")
    {
        if (CommandCTX != null) CommandCTX(caller, ctx);
    }
}



进一步抽象每个命令的执行功能都可能出现。但是,我们现在不讨论。

Further abstractions are possible in each Command's execute function. But we won't discuss that now.

下面就是这样的设计的确并不会做的事:

Here's what this design does and doesn't do:


  1. 它允许任何完成任务来更新它首先在MultiCommand类设置线程上新的上下文。

  2. 这是假设没有基于状态的必要流程。该职位仅仅表明了一堆任务只需要异步运行,而不是在一个有序的异步方式。

  3. 无CurrencyManager的,因为我们是靠异步任务的每个命令的关闭/完成返回创建它!

  4. 的线程上执行新的环境是必要的
  1. It allows any finished task to update the new context on the thread it was first set in the MultiCommand class.
  2. This assumes there is no workflow based state necessary. The post merely indicated a bunch of task only had to run asynchronous rather than in an ordered asynchronous manner.
  3. No currencymanager is necessary because we are relying on each command's closure/completion of the asynchronous task to return the new context on the thread it was created!

如果您需要并发那么这意味着上下文状态是很重要的,设计是与此类似,但不同的。设计是使用函数和回调为封轻松实现。

If you need concurrency then that implies that the context state is important, that design is similar to this one but different. That design is easily implemented using functions and callbacks for the closure.

这篇关于如何共享多命令模式不同的线程在C#中同样的背景下?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆