Este modelul singleton predispus la probleme de siguranță a firelor? (Inginerie software, Orientat Pe Obiecte, Multithreading, Singleton)

DezvoltatorDon a intrebat.
a intrebat.

Este modelul singleton predispus la probleme de siguranță a firelor? Dacă da, care sunt cele mai bune metode de a le rezolva?

Comentarii

  • Ei bine, depinde foarte mult de limbă. –  > Por Martin York.
4 răspunsuri
Yusubov

Este heavily depend on the programming language specification & how thread safety is you implemented.

De exemplu: codul furnizat mai jos utilizează blocarea dublu verificată, care nu ar trebui să fie utilizată înainte de J2SE 5.0, deoarece este vulnerabilă la bug-uri subtile.

public class Singleton {
        private static volatile Singleton instance = null;

        private Singleton() {   }

        public static Singleton getInstance() {
                if (instance == null) {
                        synchronized (Singleton.class){
                                if (instance == null) {
                                        instance = new Singleton();
                                }
                      }
                }
                return instance;
        }
}

Aici este un articol de referință despre cum să implementați corect thread safe Modelul Singleton în C#.

Comentarii

  • O implementare corectă în Java este, de fapt, complet trivială: private static Singleton instance = new Singleton(); public static Singleton getInstance() { return this.instance; } – asta e tot. Porcăria de blocare dublu verificată este o pistă roșie care continuă să fie repusă în discuție de oamenii cărora le place să despice firul în patru. –  > Por Michael Borgwardt.
  • Trebuie să fiu de acord cu Michael. Plângerea tuturor cu privire la singleton și siguranța firelor de execuție presupune că această instanță unică este creată și ștearsă pe toată durata de viață a programului. Dacă acesta este cazul, atunci au dreptate. Cu toate acestea, în TOATE sistemele pe care le-am văzut vreodată, singletonii sunt creați la pornire și există pe toată durata de viață a programului. În acest caz, toate chestiile legate de blocare și de siguranța firelor de execuție nu au niciun sens. Acum, plângându-se de singleton din cauza datelor globale și a motivelor greu de testat, sunt plângeri absolut valabile. –  > Por Dunk.
  • Poate că „rahatul de blocare dublu verificată” este adus în discuție pentru că cineva, undeva, la un moment dat, a avut de fapt această problemă. –  > Por James.
  • Iată o referință care discută modelul de blocare dublu verificată în cazul singletonului în C++. aristeia.com/Papers/… Autorii sunt Scott Meyers și Andrei Alexandrescu, care cred că, în general, fac o treabă destul de bună explicând problemele din C++. –  > Por DezvoltatorDon.
  • Eu arăt spre condiția „atunci când este utilizat înainte de J2SE 5.0” – în acel moment este util să se ia în considerare „modelul de blocare dublu verificat” – -.  > Por Yusubov.
Oded

Dacă este bine implementat, având în vedere threading-ul, un singleton va fi thread safe.

Există multe implementări în multe limbaje care nu sunt thread safe – a se vedea acest articol de Jon Skeet cu privire la Singletonul în C#. Cele mai multe dintre implementări suferă.

Cele mai bune modalități de a le „ocoli” este să vă cunoașteți limbajul, să știți cum funcționează cu firele de execuție și să vă asigurați că codul este „thread safe”.

Doar pentru a nota – chiar dacă singletons ar fi cumva de la sine siguri pentru fire, nu ar trebui să îi folosiți din acest motiv. Acestea tind să fie folosite în exces și să creeze un cod imposibil de testat ca sursă de stare globală.

Comentarii

  • +1 pentru menționarea stării globale, starea globală este predispusă la probleme de siguranță a firelor, în orice formă, singleton sau altfel. –  > Por Jimmy Hoffa.
  • Clasele singleton nu trebuie să dețină starea. Cu excepția cazului în care nu sunt proiectate în acest sens. Starea globală își are locul ei. –  > Por MebAlone.
  • @MebAlone un singleton se referă la o singură instanță globală, aceasta este definiția stării globale. Da, își are locul, dar nu poți scrie un model singleton care să nu partajeze starea decât dacă este o instanță singleton a lui null. –  > Por Jimmy Hoffa.
  • Nu toate clasele au variabile de clasă. Clasele care nu au variabile de clasă nu dețin stare. Dar clasa poate fi un singleton a cărui instanță este partajată de toți clienții. De acord că nu este o problemă, deoarece dacă clasa nu ar fi un singleton, apelurile la new nu ar aloca memorie, ci doar pointeri la aceleași metode. –  > Por MebAlone.
Telastyn

Da, așa cum au menționat și alte răspunsuri, este poate fi implementată într-o manieră sigură pentru fire. Acestea fiind spuse, tinde să fie predispus la probleme, deoarece necesită deja o implementare atentă pentru a evita problemele subtile datorate ordinii de inițializare. Posibilitatea accesului la mai multe fire de execuție exacerbează aceste preocupări.

Și este încă o stare globală. Chiar dacă singletonul în sine este threadsafe, dependența de starea globală tinde să adauge erori la codul real multithreaded.

user204677

Cel mai bun mod de a evita problemele de siguranță a firelor cu un singleton este să nu le folosești 😀 Acestea fiind spuse, dacă le vei folosi, dacă sunt sau nu sigure pentru fire într-o formă naivă depinde foarte mult de limbaj. Dacă există o problemă de siguranță, aceasta constă în natura leneșă de inițializare a singletonilor, care ar putea sfârși prin a fi executați în paralel.

Lăsând asta la o parte, să spunem că lucrați într-un limbaj în care este nu thread-safe. Acesta a fost cazul meu în anii ’90, cu o bază de cod C care a fost migrat în C++, unde dezvoltatorii au început să se bucure de modele de proiectare, inclusiv de singletons. Singurul lucru pe care v-aș ruga să nu-l faceți aici pentru a obține siguranța firelor este să începeți să încercați să faceți lucruri sofisticate, cum ar fi blocarea cu dublă verificare. În loc să faceți salturi pe spate și să jonglați cu drujbe, există o soluție foarte simplă la această problemă dacă insistați să folosiți singletoni:

Asigurați-vă că singletonul este inițializat în firul principal înainte de a fi accesat în alte fire.

Asta e tot. Este o soluție atât de simplă și nu este mare lucru de aplicat. Nu trebuie să găsiți o modalitate care să vă dea bătăi de cap pentru a accesa singletonul fără să suportați costurile de blocare în cazul obișnuit. Asigurați-vă doar că este inițializat în firul principal înainte ca alte fire să aibă acces la el. S-a făcut. Acum puteți să faceți funcția de acces fără blocare și să vă continuați viața.