WaitHandle是最好的选择吗?

时间:2013-03-11 03:07:17

标签: c# multithreading asp.net-mvc-3 waithandle

我正在开发一个MVC应用程序,它在后台使用一些Windows Workflow进行自动化。

我已经实现了一些代码来等待Workflow完成。下面是一个示例应用程序,将问题归结为其关键部分。

这个问题与WF活动中的工作没有关系,更多的是我等待它完成的工作。

HomeController.cs

    public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public JsonResult ProcessRequest()
        {
            int[] arr = new int[0];

            var wh = new ManualResetEvent(false);
            var instance = new Activities.SampleCodeActivity();
            var args = new Dictionary<string, object>();
            args.Add("Limit", 25);
            var app = new WorkflowApplication(instance, args);
            app.Completed = resultArgs =>
            {
                var list = (List<int>)resultArgs.Outputs["Primes"];
                arr = list.ToArray();
                wh.Set();
            };
            app.Run();
            wh.WaitOne();
            return Json(arr);
        }

Index.cshtml

    @{ ViewBag.Title = "Index"; }

<script src="../../Scripts/jquery-1.7.1.min.js"></script>
<script type="text/javascript">
    var tools = {};
    tools.processRequest = function () {
        $.ajax({
            url: "@Url.Action("ProcessRequest")", type: "POST",
            success: function (data) {
                alert(data);
            }
        });
    };
    $(document).ready(function () {
        tools.processRequest();
    });
</script>
<h2>Index</h2>

SampleCodeActivity.cs

public class SampleCodeActivity : CodeActivity
{
    public InArgument<int> Limit { get; set; }
    public OutArgument<List<int>> Primes { get; set; }
    private List<int> _list = new List<int>();
    protected override void Execute(CodeActivityContext context)
    {
        var limit = context.GetValue(Limit);
        checkForPrimes(limit);
        context.SetValue(Primes, _list);
    }

    private void checkForPrimes(int limit)
    {
        for (var x = 2; x <= limit; x++)
            if (isPrime(x)) _list.Add(x);   
    }
    private bool isPrime(int value)
    {
        for (var x = value - 1; x > 1; x--)
            if (value % x == 0) return false;
        return true;
    }
}

我的问题是关于Controller Action中的WaitHandle / ManualResetEvent。有没有更好的方法来使用任务等来实现这一点?我使用的是.NET 4.5。

如果没有WaitHandle,Action将在工作流程完成之前返回。

我熟悉WaitHandle,但感觉就像一个笨重的解决方案。

感谢任何帮助/指导。

1 个答案:

答案 0 :(得分:2)

WaitHandle是一个抽象类,提供在操作系统级别等待访问共享资源的能力。如果您希望在此级别同步访问权限,则无法使用它。但是,正如您所提到的,使用类似ManualResetEvent之类的内容可能会中断代码流,使得在出现问题时难以阅读和诊断。

.NET框架最近添加的许多关于线程的尝试都试图解决这个问题。在.NET 4中引入了Task的概念,它可以在某种程度上简化代码,并在该基础结构之上构建C#5以引入async/await关键字。下面的代码是一个简单的控制台应用程序,显示了使用ManualResetEventTaskasync/await实现所需内容的三种方法。

重要的是要意识到所有三个都在某个级别使用WaitHandle类来同步线程,但使用Taskasync/await来提高可读性。

class Program
{
    static void Main(string[] args)
    {
        List<int> results;

        //Using raw Wait Handle
        ManualResetEvent handle = new ManualResetEvent(false);
        Thread thread = new Thread(o =>
            {
                //Long running process
                results = LongRunningTask();
                handle.Set();
            });
        thread.Start();
        handle.WaitOne();

        Console.WriteLine("Thread completed");

        //Using Tasks
        Task<List<int>> task = Task<List<int>>.Factory.StartNew(LongRunningTask);
        results = task.Result;
        Console.WriteLine("Task completed");

        //Using async/await
        results = LongRunningTaskAsync().Result;
        Console.WriteLine("Async Method completed");

        Console.ReadLine();
    }

    public static List<int> LongRunningTask()
    {
        Thread.Sleep(5000);
        return new List<int>();
    }

    public static async Task<List<int>> LongRunningTaskAsync()
    {
        return await Task<List<int>>.Factory.StartNew(LongRunningTask);
    }
}