logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Czy zmienne volatile rozwiązują problem synchronizacji w C?

sxus 29 Mar 2012 19:58 1363 15
  • #1 10733908
    sxus
    Poziom 10  
    Nie mogę pojąć czy zadeklarowanie zmiennej jako volatile rozwiązuje problem synchronizacji. Próbowałem napisać kod bez użycia zmiennych volatile, jednak on nie działa z uwagi na optymalizację przeprowadzaną przez kompilator.
    
    struct
    {
      uint32_t semafor : 2;
      uint32_t inne_pola : X;
    } zmienna;
    
    //gdzieś z main
    cli();
    zmienna.semafor++;
    sei();
    //operacje na innych polach struktury zmienna
    zmienna.semafor--;
    
    void irq_service(void)
    {
      if (!zmienna.semafor)
      {
        //operacje na innych polach struktury zmienna
      }
    }
    


    Moje pierwsze pytanie brzmi, czy można na chwilę potraktować zmienną jako volatile, czyli instrukcję między cli a sei?
    Czy zadeklarowanie zmiennej jako volatile rozwiązuje problem? Nie można zmienić tylko wybranych bitów w pamięci, więc przynajmniej jeden bajt musi być przepisany do rejestrów, potem ustawione te bity i znopwu zapisany do pamięci:
    
    skopiuj_zmienną_z_pamięci_do_rejestru;
    ustaw_bity;
    IRQ!!!
    zapisz_zmienną_do_pamięci;
    //to co zostało zmienione w przerwaniu jest teraz tracone
    
    IRQ:
    skopiuj_zmienną_z_pamięci_do_rejestru;
    ustaw_inne_bity;
    zapisz_zmienną_do_pamięci;
    


    Już całkiem zgłupiałem 8-O .
  • #2 10734096
    eleproject

    Poziom 17  
    Volatile to volatile - zawsze wyłącza optymalizację kodu dla zmiennej. Wtedy każda instrukcja zmiany wartości danej zmiennej musi skutkować zmianą jej wartości wprost w pamięci danych. Zmienna opatrzona volatile nie jest nigdy tymczasowo 'przenoszona' do rejestrów roboczych procesora. Niezależnie gdzie ta zmiana wartości jest określona (czy w funkcji obsługi przerwania, czy w pętli głównej, czy w jakiejś innej funkcji), zawsze nastąpi modyfikacja jej wartości!
  • #5 10734137
    dondu
    Moderator na urlopie...
    grosiu2 napisał:
    Ehhh - wiesz o co chodzi a się czepiasz!

    Chodzi o to, byś podpowiadał tak, by nie było wątpliwości.
    Opisz to więc tak by autor tematu nie nauczył się czegoś, co jest niezgodne ze stanem faktycznym
  • #7 10734297
    sxus
    Poziom 10  
    Niestety nie masz racji grosiu2, w procesorach typu RISC wszystkie operacje są wykonywane na rejestrach. Więc jeśli chcę ustawić jeden bit w bajcie, to muszę ten bajt przekopiować do rejestrów, wykonać operację i znowu przekopiować do pamięci.
  • #9 10734312
    michalko12
    Specjalista - Mikrokontrolery
    sxus: Sam prosisz się o problemy.

    Nie modyfikuj pól bitowych jednocześnie w przerwaniach i gdzieś w programie bo Ci się wszystko rozjedzie. Jeśli już coś takiego musisz robić to poza przerwaniami wszystkie operacje modyfikowania pól bitowych muszą być wykonywane atomowo.
  • #10 10734327
    sxus
    Poziom 10  
    Jeśli procesor wejdzie w tryb obsługi przerwania to operacja RMW zostanie przerwana, a w przerwaniu ta sama zmienna może przyjąć nową wartość, po powrocie z obsługi przerwania, dane ustawione w zmiennej mogą zostać utracone, jeśli przerwanie nastąpi między operację M a W.
  • #11 10734348
    michalko12
    Specjalista - Mikrokontrolery
    Nie do końca rozumiem co chcesz osiągnąć, bo strasznie niejasno opisałeś problem.

    Jeśli chcesz "na chwilę" zmienić jakis obszar pamięci na volatile lub odwrotnie to możesz to zrobić poprzez wskaźniki i odpowiednie rzutowania wycinające lub dodające kwalifikator volatile
  • #12 10734446
    sxus
    Poziom 10  
    No właśnie problem w tym, że operuję na polu bitowym i nie mogę przypisać go do wskaźnika.

    Napisałem jeszcze coś takiego ale nie działa:
    
    #define sync_busy(var){ \
    cli(); \
    volatile uint8_t sync_busy_value = var; \
    sync_busy_value++; \
    var = sync_busy_value; \
    sei(); }
    


    Można też zadeklarować pole bitowe jako volatile, ale to też nie działa.
  • #13 10734515
    michalko12
    Specjalista - Mikrokontrolery
    sxus napisał:
    No właśnie problem w tym, że operuję na polu bitowym i nie mogę przypisać go do wskaźnika.


    Nie na pojedyncze pole tylko na całą strukturę
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #14 10734541
    sxus
    Poziom 10  
    No tak, tylko że operuje na różnych strukturach o różnych typach i chciałem napisać uniwersalny kod.
  • #15 10734559
    michalko12
    Specjalista - Mikrokontrolery
    Co to znaczy różne typy, różne struktury i uniwersalny kod do nich?
  • #16 10734578
    sxus
    Poziom 10  
    No że mam w każdego typu strukturze jedno pole przeznaczone na semafor, potem wykonuję wyżej wypisane makro na tym polu.

    Dodano po 15 [minuty]:

    Jest, jest, rozkminiłem to, jednak dodanie modyfikatora volatile przy definicji pola rozwiązuje problem, wcześniej omyłkowo dodałem modyfikator do nie tego pola co trzeba.
    
    struct
    {
      volatile uint32_t semafor : 2;
      //inne pola
    } zmienna;
    
REKLAMA