2014-10-30 3 views
5

So beginne ich mich mit C++ 11 <atomic> Arten vertraut machen. In der Vergangenheit, als ich eine atomare Flagge hatte, würde ich normalerweise einfach einen Mutex sperren, bevor ich darauf zugreife. Eine allgemeine Notwendigkeit wäre, zu überprüfen, ob das Flag false ist, und wenn ja, setze es atomisch auf true und dann etwas tun. Also im Grunde wäre dies wie dies erreicht werden, wo flag ist ein einfaches bool:Grundlegende Verwendung von Bedingungen mit std :: atomic <T>

{ 
    std::lock_guard<std::mutex> lock(my_mutex); 
    if (!flag) 
    { 
     flag = true; 
     // do something; 
    } 
} 

So, jetzt ich versuche, herauszufinden, wie das gleiche kann mit <atomic> erreicht werden. Die docs sagen, dass der Zuweisungsoperator und operator T eines atomaren Typs atomare Operationen sind. Allerdings, wenn ich flag zu std::atomic<bool> ändern, ich denke, ich kann nicht einfach sagen:

if (!flag) 
{ 
    flag = true; 
    // do something 
} 

... weil, obwohl der Ausdruck (!flag) atomar ist, und die Zuordnung flag = true ist atomar, gibt es nichts, einen anderen Thread zu verhindern zwischen dem Ändern des Flags zwischen diesen beiden Anweisungen.

Also, wenn ich das richtig hier, die einzige richtige Verwendung verstehen - bei allen - von conditionals mit atomaren Typen, in dem das Ergebnis der bedingten die atomare Variable ändern könnte, ist das verwenden Vergleichs- und Auslagerungsoperation ? Hab ich recht?

Also, ich würde sagen:

bool expected = false; 
if (flag.compare_exchange_weak(expected, true)) 
{ 
    // do something 
} 

Bin ich in meinem Verständnis korrigieren hier?

+2

['std :: atomic_flag'] (http://en.cppreference.com/w/cpp/atomic/atomic_flag) existiert genau für den Anwendungsfall, den Sie beschreiben, und außerdem ist es garantiert kostenlos auf allen Plattformen. Sie würden die Methode "test_and_set" verwenden, die atomar ist.Sie können auch eine 'std :: atomic ' verwenden und einen 'fetch_add' darauf ausführen, der atomar ist und Ihnen den vorherigen Wert zum Zeitpunkt der Inkrementierung gibt (dies ist oft schneller als ein CAS auf den meisten Architekturen, obwohl ich mir nicht schneller vorstelle als 'std :: atomic_flag', was in diesem Fall meine Präferenz wäre). – Cameron

+0

Richtig - aber es scheint, es gibt keine Möglichkeit, den Wert einer atomaren Flagge einfach atomar "zu überprüfen" (ohne es zu setzen) - oder gibt es? Die Dokumente definieren keine 'operator bool' oder was immer den Ausdruck' if (flag) 'ermöglichen würde. Ich weiß, dass ich diese Anforderung in meiner Frage nicht angegeben habe - ich frage mich nur. Apropos ... warum * gibt es keine Möglichkeit, einfach die atomare Flagge zu überprüfen, ohne sie zu setzen? – Siler

+0

Das ist richtig, Sie müssen es einstellen, um es zu testen (das entspricht Ihrem Beispielcode, wie er derzeit geschrieben wird, außer dass er atomar ist). Wenn Sie es unabhängig testen müssen, schlage ich vor, die 'fetch_add'-Methode oder' compare_exchange_strong' zu verwenden (was viel übersichtlicher ist und [so schnell wie 'fetch_add' (' lock xadd] auf x86] ist (http: // www.agner.org/optimize/instruction_tables.pdf)). – Cameron

Antwort

3

Wenn Sie mehrere Threads, die denselben Code ausführen, dass die Flip tun müssen, ja - Sie müssen compare_exchange_weak() oder compare_exchange_strong() für das genau der Grund, verwenden Sie vorschlagen (wahrscheinlich stark bevorzugen).

Es ist jedoch nicht der Fall zu sagen, dass dies die nur ordnungsgemäße Verwendung von Bedingungen mit Atomics ist. Wenn ich, sagen wir, ein Thread, der immer nur die atomare und man liest, die sie schreibt, ist es durchaus sinnvoll sie die einfache Art und Weise zu verwenden, ... zB:

std::atomic<bool> done{false}; 

// thread 1 
while (!done) { 
    .... 
} 

// thread 2 
stop() { done = true; } 

Es gibt keinen Grund für mich zu tun done.compare_exchange_strong(expected, true) dort. Das ist Overkill. Es ist wirklich von Fall zu Fall.

+0

Aus dem OP-Code geht hervor, dass "compare_exchange_ {weak, strong}" in diesem Fall geeignet ist. Die Frage qualifiziert das Wort "nur" mit der Bedingung, dass das Ergebnis des Vergleichs verwendet wird, um zu entscheiden, ob die Zuweisung erfolgt. Dennoch eine gute und gründliche Antwort für die weiteren Anwendungsfälle. –

1

Ja.

Davon abgesehen, können Sie dafür compare_exchange_strong bevorzugen, es sei denn, Sie sind in einer engen Schleife. Es kann zu einer verminderten Leistung führen, garantiert Ihnen aber das Ergebnis, das Sie erwarten (was nicht compare_exchange_weak ist).

0

Offensichtlicher Hinweis: Lock-Semantik ist ziemlich anders als nur atomare Prüfung, da in diesem Fall der andere Thread wartet, bis Sperre freigegeben wird und seine Aktionen immer ausführen, nachdem Sperre erworben ist. Genau genommen sind also zwei Codebeispiele nicht gleichwertig.