C# 多线程:计算器池

C# MultiThreading: pool of calculators

我想要一个静态(全局)计算器池,它将被许多不同的线程访问。 经过一些研究,我发现数组的元素是线程安全的。 我认为将不同的计算器(直到运行时数量未知)存储在静态数组(计算器[]计算器)中是个好主意。

如何确保一台计算器只使用一台计算器?
我阅读了整个 msdn 文档,所以请不要 post "only" 链接。

我也考虑过布尔数组"locked"但是我找不到实现这个线程安全的方法。

到目前为止我的代码:

internal static class Calculators
{
private static Semaphore pool;
private static bool[] locked;
private static calcs[] neuralNetworks;
private static Thread[] threads;
internal static Calculators(){
    int number = Globals.Number;

    pool = new Semaphore(number, number);
    locked = new bool[number];
    calcs = new calcs[number];
    threads = new Thread[number];

    for (int index = 0; index < number; index++)
    {
        // all neuralNetworks are unlocked by default
        locked[index] = false;

        // generate one network per "countThreads"
        calcs[index] = Globals.CalcObj;

        // generate one thread for each neural network
        threads[index] = new Thread(new ThreadStart());
    } 
}
private int WhichCalculators() 
{
        int index;
        for (index = 0; index < countThreads; index++)
        {
            if (locked[index] == false) 
            {
                locked[index] = true;
                return index;                
            }          
        }
        throw new Exception("Calculators was called, but there weren't any networks unused");
}

}

代码更新: 如果我在这个方法中调用 "WhichCalculator()" 那么它应该工作吗?

private static void doStuff()
{
pool.WaitOne();
Monitor.Enter(thisLock);
        try
        {
            int whichCalculator = WhichCalculator();
            locked[whichCalculator] = true;

            lock (calculators[whichCalculator])
            {
                Monitor.Exit(thisLock);

                // do stuff

                locked[whichCalculator] = false;
            }
        }
        catch 
        {
            Monitor.Exit(thisLock);
        }
        //Calculate(); 

        pool.Release();
}

问题 2: 我是否正确地假设,静态构造函数将在第一次(但之前)此 class 或其任何成员将被访问时立即执行?

您可以 lock 您的阵列。这将确保每个数组操作都是线程安全的。

为确保每个对象一次仅使用一次,您可以为其添加一个标志,如 calculator.InUse。如果无法向 class 添加标志,则可以使用 extension method.

是的,你必须使用锁。但是又是数组和计算器的每个实例。

如果您可以在开始代码的多线程部分之前填充数组,则您也不需要锁定数组(由于静态内容,仅读取不会造成问题)但是调整数组大小需要锁定对其的每次访问(写入和读取)。 所以您的代码可能如下所示:

Calculator calc = null;
lock(calculators)
{
    calc = calculators[0];

}
lock(calc)
{
    // ... do stuff
}

这样数组就不再需要锁定了,您可以锁定计算器本身。