-2

I want to have a static (global) pool of calculators which are going to be accessed by a lot of different threads. After some researching I found out that the elements of Arrays are threadsafe. I thought that it would be good idea to store the diffrent calculators (amount unknown until runtime) in a static array (calculator[] calculators).

How do I ensure that only one calculator is being used by one calculator?
I read the whole msdn documentation so don't post "only" links please.

I have also thought about a bool array "locked" but I can't find a way to implement this threadsafe.

My code so far:

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");
}

}

Code Update: So should it work, if I call "WhichCalculator()" in this method?

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();
}

Question 2: Am I right to assume, that the static constructor is going to be executed as soon as (but before) the first time this class or any member of it is going to be accessed?

ginfx
  • 3
  • 1
  • 4
  • 1
    Please post some code as to what you've done so far/your thoughts on what to do – oppassum Jul 09 '15 at 14:21
  • 1
    Just because the items of an array are thread-safe, doesn't mean operations with items contained in the array are thread-safe. For example, incrementing the value of an element in an array is not thread safe. – Ron Beyer Jul 09 '15 at 14:22

2 Answers2

1

Yes you have to use lock. But the array and every instance of calculator again.

If you can fill the array before you start the multithreaded section of your code you need not lock the array as well (only reading doesn't make problems due to the static content) but with resizing the array you need to lock every access to it (writing AND reading). So your code could look like this:

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

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

This way the array isn't longer locked then needed and you can lock the calculator itself.

  • Thanks mate. I tired this at first but I quickly came to documentation, saying its bad practice to lock a "non-object". Is this true? Is there another way? Plus, wouldn't this only execute one calculator by the time, as there is only one "calc" ? – ginfx Jul 09 '15 at 14:38
  • In my opinion locking the instance variable which causes critical situations is the best choice (and simplest of course) yeah of course the code itself doesn't make that much sense^^ I wanted point out how to lock and what to lock at what time. For a more complex nesting of locks you should use the [Monitor](https://msdn.microsoft.com/de-de/library/system.threading.monitor(v=vs.110).aspx) class. The lock keywoard is a shortcut for Monitor.Enter(..);...Monitor.Exit(..); – Sebastian Kaupper Jul 09 '15 at 14:48
  • Would it be bad, if I would go for " lock(calculators[0]) ? – ginfx Jul 09 '15 at 15:34
  • *Update* Could you check on my new code, please? Im new at multithreading and not sure if I debug it propertly. – ginfx Jul 09 '15 at 16:07
  • For me it seems that your code should work although I don't see where you declared 'thisLock' but as long as it exists (and is not null) it should be enough. Instead of your locked array you could also use Monitor.TryLock as a little improvement but I don't think it causes not thread-safe code. – Sebastian Kaupper Jul 10 '15 at 10:34
0

You can lock your array. That would ensure that every array-operation is executed thread-safe.

To ensure, that each object is only used once at a time you can add a flag to it, like calculator.InUse. If you can't add a flag to the class, you can use an extension method.

Community
  • 1
  • 1
Patrik
  • 1,355
  • 12
  • 22
  • But I don't want to lock the array itself. I want that every calculator in the calcualtor array is working. Im worried that my implentation involving a flag will not be threadsafe. – ginfx Jul 09 '15 at 14:27