2016-04-05 17 views
0

habe ich eine sehr similiar Frage 2012.Kritische Abschnitte und Rückgabewert durch Bezugnahme in C++

Critical Sections and return values in C++

schon gefragt Ich mag würde einen Container Thread-sicher aswell zuzugreifen, sondern eine im Cache gespeicherte Version durch Verweis zurückgeben .

struct Container { 
    const Data& getSomeData() const { 
    EnterCriticalSection(& myCritSec); 
    if (update) { 
     cache.calulatefromcontainer();   
    } 
    // fill retobj with data from structure 
    LeaveCriticalSection(& myCritSec); 
    return cache; 
    } 

private: 
    mutable Data cache; 
}; 

Das Problem ist, dass "Return-Cache" -Linie nicht mehr geschützt ist. Ist es möglich, "Cache" thread sicher als Referenz zurückzugeben?

+2

Die Rückgabe eines Verweises auf änderbare Daten ist grundsätzlich kein Problem für threadsichere Container. Nicht viel, um hier zu deplazieren. – SergeyA

Antwort

0

Sie müssen darüber nachdenken, was Ihr kritischer Abschnitt eigentlich schützt.

In Ihrem Code sieht es so aus, als ob myCritSec den Container schützt. Aber vor allem ist es nicht Schutz der cache Mitgliedsvariable. Das liegt nicht an der Zeile, sondern daran, dass Sie einen Verweis darauf zurückgeben, so dass es uneingeschränkt von Client-Code verwendet werden kann, während andere Threads getSomeData() erneut aufrufen und sie ändern.

Eine Lösung wäre, eine Kopie der Daten zurückzugeben.

Eine andere Lösung wäre, dass jede öffentliche Funktion, die zum Abrufen von Informationen aus Data verwendbar ist, irgendwie die myCritSec des übergeordneten Containers verwendet. Das Problem bei diesem Ansatz ist, dass es sehr leicht wäre, in Rennen zu geraten. Zum Beispiel:

class Data 
{ 
public: 
    int getA() const 
    { 
     int res; 
     EnterCriticalSection(parentCS); 
     res = getAunlocked(); 
     LeaveCriticalSection(parentCS); 
     return res; 
    } 
    int getB() const 
    { 
     int res; 
     EnterCriticalSection(parentCS); 
     res = getBunlocked(); 
     LeaveCriticalSection(parentCS); 
     return res; 
    } 
}; 

Und dann in der Benutzercode:

const Data &data = container.getSomeData(); 
if (data.getA() == data.getB()) // <--- RACE!!! 
{ 
} 

Seit dem Aufruf an getA() und getB() jeweils Verriegelung und die CS Entriegeln, ein anderer Thread könnte die Daten einfach mal zwischendurch ändern und erstellen eine Wettlaufbedingung.

+0

Also die einzige wirklich sichere Lösung wäre eine Kopie der Daten? –

+0

@vcduser: "Die einzige echte sichere Lösung"? Es gibt viele Möglichkeiten, Dinge richtig zu machen. Sie können beispielsweise den CS-Behandlungscode dem Benutzer des Containers hinzufügen, wenn Sie ihm beispielsweise vertrauen können. Oder Sie können Teilmengen der Daten kopieren, oder Sie können Copy-on-Write-Techniken, gemeinsame Zeiger verwenden ... – rodrigo