Windows Forms, BackgroundWorker

0

Więcej niż jeden obiekt backgroundWorker (dzialaja w petli) modufikuja zmienną zadeklarowaną jako prywatna zmienna formy.
Domyślam się, że należałoby tutaj zastosować jakąś synchronizacje.
Wskazówki, jak zrobić to prawdiłowo ?

1

jeśli jest to zmienna typu prostego (int, double, ...) to nie ma takiej potrzeby. Jeśli nie to możesz użyć lock, mutex, samphor - w googlach naprawdę jest to dobrze opisane

0

Czyli obiekty backgroundWorker są już w jakiś sposób zabezpieczone przed potencjalną chęcią odwołania się do danej zmiennej przez więcej niż jeden obiekt tego typu jednocześnie ? A może jest to po prostu niegroźne ?

0

operacje na zmiennych prostych są niegroźne, co innego np. obiekty, tablice, struktury czy ciągi znaków

2

Czyli obiekty backgroundWorker są już w jakiś sposób zabezpieczone przed potencjalną chęcią odwołania się do danej zmiennej przez więcej niż jeden obiekt tego typu jednocześnie

Nie, nie są. Chodzi o to, że w niektórych ograniczonych przypadkach jest to niegroźne.

Problem nie jest w „potencjalnej chęci odwołania się do zmiennej jednocześnie”, bo to zawsze działa, ale w tym, jakie to może mieć konsekwencje.

Na przykład, jeśli jeden wątek czyta zmienną, a drugi zapisuje, to wystarczy że zmienna będzie volatile i nie trzeba dodatkowej synchronizacji.

Przy czym „zapisuje” należy rozumieć ściśle. x++ to nie tylko zapis, ale i odczyt: x=x+1.

Jeśli kilka wątków robi takie x=x+1, to jeden może odczytać zmienną, drugi w tym samym czasie odczytać zmienną, pierwszy zwiększy o jeden, zapisze, drugi zwiększy o jeden oryginalną wartość, zapisze, i w rezultacie x zwiększył się o 1 zamiast o 2.

Wszystko więc zależy od tego jak wygląda kod.
Dla pewności używaj właściwych mechanizmów synchronizacji. Oprócz locków i mutexów, do operacji na pojedynczych zmiennych pod Windows masz funkcje InterlockedExchange i okoliczne, w .NET klasę Interlocked.

0

Czyli jeśli w 'formie' deklaruje tablicę:

array<int> ^Diods = gcnew array <int>(6);

To utworzenie w wątku nowej zmiennej tego samego typu i wywołanie funkcji Exchange:

array<int> ^ExDiods = gcnew array <int>(6);
Interlocked::Exchange(Diods, ExDiods);

I posługiwanie się w wątku zmienną ExDiods jest wystarczające?

0

Rzeczywiście coś pomieszałem.
Robię więc tak, że w wątku, w którym modyfikuję wartości Diods, tworzę ExDiods i ExDiods modyfikuję, a następnie komendą Exchange "podmieniam" (jeśli można to tak nazwać) i wygląda na to, że działa poprawnie.

Co natomiast z synchronizacją w wątku, w którym tylko odczytuję wartości z Diods i przepisuję je do innej tablicy. Czy tam również synchronizacja jest potzebna ?

0

Hej, przeanalizuj sobie jak można wykorzystać sekcję krytyczną.

 
#include <windows.h>

class CSomeClass
{
public:
    CSomeClass()
    {
        InitializeCriticalSection(&m_csCriticalSection);
    }
    ~CSomeClass()
    {
        DeleteCriticalSection(&m_csCriticalSection);
    }
    
    int getIntSave(int a_iIndex)
    {
        int iRetval;
        EnterCriticalSection(&m_csCriticalSection);
        iRetval = m_aGlobalArray[a_iIndex];
        LeaveCriticalSection(&m_csCriticalSection);
        return iRetval;
    }
    
private:
    int m_aGlobalArray[5] = {0,1,2,3,4};
    CRITICAL_SECTION m_csCriticalSection;
};
0

Diods

Co to jest “diods”?

Co natomiast z synchronizacją w wątku, w którym tylko odczytuję wartości z Diods i przepisuję je do innej tablicy. Czy tam również synchronizacja jest potzebna

Jeśli w tym wątku tylko odczytujesz, a w tamtym podmieniasz wypełnioną już tablicę, to wątek odczytujący odczyta albo całą nową, albo całą starą - czyli dobrze. Synchronizacja służy zapobieganiu odczytu danych częściowo nowych a częściowo starych.

0

Ostatecznie ograniczyłem się tylko do jednego wątku dodatkowego, ale zmienne

 array<int> ^Diods = gcnew array <int>(6);

odpowiadające za przechowywanie danych, które mają być przekazywane do mikrokontrolera ciagle sa deklarowane w klasie "forma", dlatego ze zmienne te moga byc rowniez modyfikowane poprzez bezposrednie zdarzenia wywolywane w formie np. nacisniecie przycisku, przesuniecie suwaka, etc. Dlatego tez uznalem, ze synchronizacja jednak byc powinna.

W watku najpierw pobieram dane, nastepnie w oparciu o te dane i dane pochodzace z formy modyfikuje tablice:

 array<int> ^ExDiods_K = gcnew array <int>(6);

ktora po przeprowadzeniu modyfikacji "kopiuje" do zmiennej 'Diods'

 Interlocked::Exchange(Diods, ExDiods_K);

Nastepnie "tworze kopie" zmiennej Diods:

Interlocked::Exchange(ExDiods_T, Diods); 

którą to, po odpowiednim przekonwertowaniu wysyłam do mikrokontrolera.

Robię to w ten sposób, ponieważ w miedzyczasie moze zostac wywołane zdarzenie, które rowniez będzie zmieniało wartości elementów tablicy 'Diods'

Czy ma to sens ? ^^

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