Static - thread safe

0

Czy metoda statyczna, która nie ma efektów ubocznych oraz jest bezstanowa, do której przekazuje instancje obiektu, czyli kopiuje referencje, jest bezpieczna tak długo, jak inny wątek nie może zmienić stanu owej instancji przekazanej przez parametr metody?

Metoda wykonuje prosty algorytm w pętli, który nie zmienia stanu obiektu przekazanego przez parametr, jest to prosta fabryka.

1

Wydaje się, że tak. Dopóki nie pokażesz kodu, dopóty pewności nie będzie.

0

Podajesz sprzecznie dane:

  • "... tak długo, jak inny wątek nie może zmienić stanu owej instancji ..."
  • "... który nie zmienia stanu obiektu przekazanego przez parametr ..."
0

Zablokuj ją, dla pewności. Jeśli się mylę, niech mnie ktoś poprawi:


object methodLocker = new object();

public static void MyStaticMethod(MyClass obj)
{
    lock(methodLocker)
    {
       //tutaj całe ciało
    }
}
0
_13th_Dragon napisał(a):

Podajesz sprzecznie dane:

  • "... tak długo, jak inny wątek nie może zmienić stanu owej instancji ..."
  • "... który nie zmienia stanu obiektu przekazanego przez parametr ..."

Jeśli ja przekaże tę instancję obiektu mutowalnego do 5 różnych metod współbieżnie które nie przekazują instancji jako readonly to pewnie zdąży się coś złego.

Kolega tłumaczył mi to tak, że do metody statycznej mogą się dostać na raz dwa wątki i wykonać tego samego if'a co zmieni wynik jednego "wątka" albo drugiego "wątka" na nieprawidłowy, lub obydwa "wątki" stworzą naraz tą samą instancje.
Brzmiało to tak, jak by pracował na komputerze kwantowym, lecz wydawał się bardzo przekonujący.

1

To brzmi jak opis naiwnej implementacji singletona przez double checked lock, gdzie obiekt nie jest w pełni skonstruowany, ale referencja już jest przypisana do zmiennej. Trudno wyczuć, o co dokładnie chodziło koledze.

0
Jaro123 napisał(a):

Brzmiało to tak, jak by pracował na komputerze kwantowym, lecz wydawał się bardzo przekonujący.

Nie ma to nic a nic wspólnego z komputerem kwantowym.
Musisz zrozumieć jedno podstawowe zagadnienie, jeżeli mamy do czynienia z kilkoma wątkami to nie znamy momentu przełączenia się z jednego na drugi.
Więc może to być po np porównaniu przełączamy się zaś jak wchodzimy wewnątrz bloku tego if'a to już warunek nie jest prawdą.

0

@_13th_Dragon Przestań mi wsadzać do ust to, czego nie powiedziałem...
Poza tym, co to ma wspólnego z opisanym przeze mnie problemem?

Tak jak @Afish powiedział problem pojawi się kiedy mówimy np o singletonie bez locka.

Jeśli ktoś się ze mną nie zgadza, to niech napisze test, który to udowodni, ja napisałem coś takiego:

 class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 1000; i++)
            {
                Console.WriteLine("Test Start");
                Parallel.Invoke(() =>
                {
                    var numbers = new Numbers(2, 2);
                    var sum = SumOfNumbers(numbers);

                    if (sum != 4)
                        throw new Exception("WTF....?");

                }, () =>
                {
                    var numbers = new Numbers(5, 5);
                    var sum = SumOfNumbers(numbers);

                    if (sum != 10)
                        throw new Exception("WTF....?");

                }, () =>
                {
                    var numbers = new Numbers(1, 1);
                    var sum = SumOfNumbers(numbers);

                    if (sum != 2)
                        throw new Exception("WTF....?");
                    
                });
                Console.WriteLine("Test end");
            }
            Console.ReadLine();
        }

        public static int SumOfNumbers(Numbers numbers)
        {
            int sum = 0;

            if (numbers.NumberOne == 2 && numbers.NumberTwo == 2)
                sum = 4;

            if (numbers.NumberOne == 5 && numbers.NumberTwo == 5)
                sum = 10;

            if (numbers.NumberOne == 1 && numbers.NumberTwo == 1)
                sum = 2;

            return sum;
        }
    }

    public class Numbers
    {
        public Numbers(int numberOne, int NumberTwo)
        {
            NumberOne = numberOne;
            this.NumberTwo = NumberTwo;
        }

        public int NumberOne { get; }
        public int NumberTwo { get; }
    }

Potem jeszcze tak:

 static void Main(string[] args)
        {
            Parallel.For(0, 10000, i =>
            {
                Console.WriteLine("Test Start " + i);

                var numbers = new Numbers(2, 2);
                var sum = SumOfNumbers(numbers);

                if (sum != 4)
                    throw new Exception("WTF....?");

                var numbers2 = new Numbers(5, 5);
                var sum2 = SumOfNumbers(numbers2);

                if (sum2 != 10)
                    throw new Exception("WTF....?");

                var numbers3 = new Numbers(1, 1);
                var sum3 = SumOfNumbers(numbers3);

                if (sum3 != 2)
                    throw new Exception("WTF....?");
                
                Console.WriteLine("Test end");
            });
            Console.ReadLine();
        }
0
Jaro123 napisał(a):

@_13th_Dragon Przestań mi wsadzać do ust to, czego nie powiedziałem...

Ja zacytowałem. Zmieniłeś treść posta kilka razy aby się powymądrzać?

0
_13th_Dragon napisał(a):
Jaro123 napisał(a):

@_13th_Dragon Przestań mi wsadzać do ust to, czego nie powiedziałem...

Ja zacytowałem. Zmieniłeś treść posta kilka razy aby się powymądrzać?

Nie zmieniałem kontekstu wypowiedzi dodałem, brakujące przecinki. Pisz na temat albo się w ogóle nie odzywaj.

1

Może komuś się przyda.

forum MS:

"The only variable that's accessed by your static method is a local variable, i. A local variable is allocated on the stack and each thread has a different stack. So that would be 2 "memory blocks", one for each thread. Since local variables are particular to each thread there's no need for locks or any other form of thread synchronization."

"CLR via C#, 4th Edition"

For the record, making a method thread safe does not mean that it internally takes a thread
synchronization lock. A thread-safe method means that data doesn’t get corrupted if two threads
attempt to access the data at the same time. The System.Math class has a static Max method
implemented as follows.

public static Int32 Max(Int32 val1, Int32 val2) {
 return (val1 < val2) ? val2 : val1;
}

This method is thread safe even though it doesn’t take any lock. Because Int32 is a value type,
the two Int32 values passed to Max are copied into it and so, multiple threads could be calling Max
simultaneously, but each thread is working on its own data, isolated from any other thread.

As mentioned earlier, when a thread
constructs an object, only this thread has a reference to the object, no other thread can access that
object

0

Tutaj piszesz o metodach statycznych. I to faktycznie rozwiązuje kilka wątpliwości. Natomiast singleton to coś nieco innego. I tu może się zdarzyć, że metoda singletona korzysta z pól klasy. Wtedy już trzeba locki zastosować.

1 użytkowników online, w tym zalogowanych: 0, gości: 1