所有线程完成后设置属性值?

时间:2017-11-02 09:07:43

标签: c# multithreading

在我的应用程序中有三个线程,如:

 private Thread _analysisThread;
 private Thread _head2HeadThread;
 private Thread _formThread;

并以下列方式启动每个线程:

if (_analysisThread == null || !_analysisThread.IsAlive)
{
     _analysisThread = new Thread(() => { Analysis.Logic(match); });
     _analysisThread.Start();
}

我有一个ListView,用户可以在其中选择一个项目,然后重新开始该线程,但我希望防止这种情况导致每个线程内的方法都很重,所以需要时间来完成它们。 / p>

到现在为止,我想禁用ListView选项,所以我做了:

<ListView IsEnabled="{Binding IsMatchListEnabled}">

private bool _isMatchListEnabled = true;
public bool IsMatchListEnabled
{
    get { return _isMatchListEnabled; }
    set
    {
        _isMatchListEnabled = value;
        OnPropertyChanged();
    }
}

在新线程开始之前我做:IsMatchListEnabled = false;但是我需要做的是检查所有线程是否都已完成然后执行:IsMatchListEnabled = true;,实际上如果我之后启用了ListView所有线程,我得到ListView甚至已启用&#39;因为Thread代码是异步的,Thread之外的代码是同步的,所以实际上这个属性是无用的。

我试图避免这种情况是创建一个像这样的无限循环:

while (true)
{
   if (!_analysisThread.IsAlive && !_head2HeadThread.IsAlive && !_formThread.IsAlive)
   {
          IsMatchListEnabled = true;
          break;
   }
}

在所有线程执行之后放置此循环,但是您可以想象,这将冻结应用程序。 任何解决方案?

2 个答案:

答案 0 :(得分:2)

所有评论都是正确的 - 最好使用Tasks。只是回答OP的问题。

您可以使用ManualResetEvent来同步线程,通过线程数包含一系列事件,并在所有线程完成时更改IsMatchListEnabled一个额外线程。

public static void SomeThreadAction(object id)
{
    var ev = new ManualResetEvent(false);
    events[id] = ev; // store the event somewhere

    Thread.Sleep(2000 * (int)id); // do your work

    ev.Set(); // set the event signaled
}

然后,在其他地方我们需要初始化等待例程。

// we need tokens to be able to cancel waiting
var cts = new CancellationTokenSource();
var ct = cts.Token;

Task.Factory.StartNew(() =>
{
    bool completed = false;
    while (!ct.IsCancellationRequested && !completed)
    {
        // will check if our routine is cancelled each second
        completed = 
            WaitHandle.WaitAll(
                events.Values.Cast<ManualResetEvent>().ToArray(),
                TimeSpan.FromSeconds(1)); 
    }

    if (completed) // if not completed, then somebody cancelled our routine
        ; // change your variable here
});

可以找到完整的示例并查看here

答案 1 :(得分:1)

我建议使用Microsoft的Reactive Framework。它比任务更强大,代码比使用线程简单得多。

假设您有3个长期运行的操作:

Action huey = () => { Console.WriteLine("Huey Start"); Thread.Sleep(5000); Console.WriteLine("Huey Done"); };
Action dewey = () => { Console.WriteLine("Dewey Start"); Thread.Sleep(5000); Console.WriteLine("Dewey Done"); };
Action louie = () => { Console.WriteLine("Louie Start"); Thread.Sleep(5000); Console.WriteLine("Louie Done"); };

现在您可以编写以下简单查询:

IObservable<Unit> query =
    from a in new [] { huey, dewey, louie }.ToObservable()
    from u in Observable.Start(() => a())
    select u;

你这样运行:

Stopwatch sw = Stopwatch.StartNew();
IDisposable subscription = query.Subscribe(u => { }, () =>
{
    Console.WriteLine("All Done in {0} seconds.", sw.Elapsed.TotalSeconds);
});

我得到的结果是:

Huey Start
Dewey Start
Louie Start
Huey Done
Louie Done
Dewey Done
All Done in 5.0259197 seconds.

三个5秒的操作在5.03秒内完成。全部并行。

如果您想提前停止计算,请致电subscription.Dispose()

NuGet“System.Reactive”获取位。