我如何在信号量中“WaitMoreThanOne”?

时间:2014-05-27 21:29:44

标签: c# multithreading semaphore

有没有办法可以在信号量中等待多个Release()?

说我有这样的事情:

class GoRunners {

    Semaphore runnersSemaphore;

    List<Result> results = new List<Result>();

    private void RunForestRun(object aRunner) {
        runnersSemaphore.Wait();
        Runner runner = (Runner)aRunner;
        results.Add(runner.Run());
        runnersSemaphore.Release();
    }

    private List<Result> Go() {
        List<Runners>() runners = CreateSomeRunners();
        runnersSemaphore = new Semaphore(2, 2); // At most two threads at once
        runners.ForEach((runner) => new Thread(RunForestRun).Start(runner); )}
        runnersSemaphore.WaitFor(runners.Count); //How do I do this?
        return results;
    }
}

我知道我可以在循环中使用多个WaitOne(),但这看起来不太好。但如果没有别的办法,我对它很好。如果有另一种机制可以达到我想要的效果(我曾经在使用信号量的Java中做过这样的事情,所以我的思想朝这个方向发展)。

注意:我已经锁定在.NET 3.5中:(

1 个答案:

答案 0 :(得分:3)

您需要在foreach循环中移动速率限制代码,这样在所有运行程序启动之后循环才会退出。完成后,您只需等待剩余的两个跑步者完成,然后再返回结果。

class GoRunners {

    Semaphore runnersSemaphore;

    List<Result> results = new List<Result>();

    private void RunForestRun(object aRunner) {
        try {
            Runner runner = (Runner)aRunner;

            var result = runner.Run(); 
            lock(results)
            {
                results.Add(result)//List is not thread safe, you need to lock on it or use a different threadsafe collection (I don't know if there are any in .NET 3.5)
            }
        }
        finally { //A little safety in case a execption gets thrown inside "runner.Run()"
            runnersSemaphore.Release();
        }
    }

    const int MAX_RUNNERS = 2; //I hate magic numbers in code if they get spread across more than one line, move the max out to a const variable.

    private List<Result> Go() {
        List<Runners>() runners = CreateSomeRunners();
        runnersSemaphore = new Semaphore(MAX_RUNNERS, MAX_RUNNERS); // At most two threads at once
        foreach(var runner in runners)
        {
            runnersSemaphore.WaitOne(); //This goes in here now. New threads will not be started unless there is less than 2 runners running.
            new Thread(RunForestRun).Start(runner);
        }

        for(int i = 0; i < MAX_RUNNERS; i++) {
            runnersSemaphore.WaitOne(); //Wait for the currently running runners to finish.
        }

        return results;
    }
}