C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

volatile vector iterator will nicht

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (German)
View previous topic :: View next topic  
Author Message
Marcel Müller
Guest





PostPosted: Mon Dec 26, 2005 12:23 pm    Post subject: volatile vector iterator will nicht Reply with quote



Hallo,

ich kämpfe gerade mit einer Multithread-Applikation.

Sinngemäß:

class Buffer
{ typedef std::vector<char> BufferType;
typedef BufferType::iterator BufferIterator;

BufferType Buffer; // Ring-Buffer
Mutex BufferMutex; // Plattformspezifischer Mutex-Semaphore-Wrapper
volatile BufferIterator Cursor;

public:
// Hole nächstes Stück Buffer, Maximallänge: len
Request(void*& data, size_t& len)
{ Lock(BufferMutex); // Hält die Semaphore, bis zum Lock-Destruktor
BufferIterator cur = Cursor; // hier geht der Ärger los!
size_t rem = Buffer.end() - cur; // Elemente noch im Buffer
if (rem < len)
len = rem;
data = &*cur;
cur += len;
Cursor = cur == Buffer.end() ? Buffer.begin() : cur; // neue Pos.
return;
}
...
};

Die Fehlermeldung ist sinngemäß, dass der Konstruktor
BufferIterator(volatile BufferIterator) nicht definiert ist.

Nach meinem Verständnis ist es üblich, dass die volatile-Eigenschaft
nicht automatisch mit kopiert wird. Bei PODs und C-Style Pointern
funktioniert das auch:

volatile int ri;
int li = ri;

char* volatile rp;
char* lp = rp;

Die STL-Iteratoren (in dem Fall die Implementation bei gcc) verhalten
sich aber offenbar nicht so.

Ich habe mir jetzt mit folgendem, dreckigen Konstrukt mit dem Umweg über
einen Pointer beholfen:

BufferIterator cur = *const_cast ...
*const_cast<BufferIterator*>(&Cursor) = cur ...;

Aber das kann es doch nicht sein.
Außerdem wird dadurch m.E. das volatile-Attribut in seiner Wirkung
ausgeschaltet. Dieses ist aber erforderlich, damit nicht irgend ein
Optimizer auf die Idee kommt, den Wert von WrPos über die
Lock(BufferMutex) Anweisung hinweg zu cachen. (In der realen Anforderung
läuft das Lock nicht über die gesamte Funktion, sondern besteht aus zwei
aufeinanderfolgenden, synchronisierten Blöcken, in denen jeweils auf
Cursor zugegriffen wird.


Marcel

--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de
Back to top
Stefan Reuther
Guest





PostPosted: Mon Dec 26, 2005 4:51 pm    Post subject: Re: volatile vector iterator will nicht Reply with quote



Marcel Müller wrote:
Quote:
class Buffer
{ typedef std::vector<char> BufferType;
typedef BufferType::iterator BufferIterator;
volatile BufferIterator Cursor;
[...]
BufferIterator cur = Cursor; // hier geht der Ärger los!
[...]
Die Fehlermeldung ist sinngemäß, dass der Konstruktor
BufferIterator(volatile BufferIterator) nicht definiert ist.

So ist das leider.

Quote:
Ich habe mir jetzt mit folgendem, dreckigen Konstrukt mit dem Umweg über
einen Pointer beholfen:

BufferIterator cur = *const_cast<BufferIterator*>(&Cursor);
...
*const_cast<BufferIterator*>(&Cursor) = cur ...;

Aber das kann es doch nicht sein.

Doch, anders geht's nicht. Allerdings geht auch
const_cast<BufferIterator&>(Cursor)
und spart ein paar Sonderzeichen.


Stefan

--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de

Back to top
Torsten Robitzki
Guest





PostPosted: Mon Dec 26, 2005 11:14 pm    Post subject: Re: volatile vector iterator will nicht Reply with quote



Hallo Marcel,

Marcel Müller wrote:

Quote:
Hallo,

ich kämpfe gerade mit einer Multithread-Applikation.

Sinngemäß:

snip


Quote:
Mutex BufferMutex; // Plattformspezifischer Mutex-Semaphore-Wrapper
volatile BufferIterator Cursor;


Außerdem wird dadurch m.E. das volatile-Attribut in seiner Wirkung
ausgeschaltet. Dieses ist aber erforderlich, damit nicht irgend ein
Optimizer auf die Idee kommt, den Wert von WrPos über die
Lock(BufferMutex) Anweisung hinweg zu cachen.

C++ sagt nix über multithreading, aber es gibt einige Compiler, die für
bestimmte Betriebssyteme ganz bestimmte Aussagen darüber tätigen, was
man von ihnen in erwarten kann. Mich würde wundern, wenn Du irgend wo in
diesen Dokumentationen von "volatile" im Zusammenhang mit den üblichen
Synchronisationsprimitiven gelesen hättest Smile.

"volatile" mag auf einer ganz bestimmten Platform, mit einem ganz
bestimmten Compiler den gewünschten Effekt erzeugen. Da du aber bereits
den "Plattformspezifischer Mutex-Semaphore-Wrapper" verwendest, solltest
Du Deine schwerr portable Verwendung von "volatile" überdenken ;-)

mfg Torsten

--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de

Back to top
Marcel Müller
Guest





PostPosted: Wed Dec 28, 2005 2:22 pm    Post subject: Re: volatile vector iterator will nicht Reply with quote

Hallo,

Stefan Reuther wrote:
Quote:
Ich habe mir jetzt mit folgendem, dreckigen Konstrukt mit dem Umweg über
einen Pointer beholfen:

BufferIterator cur = *const_cast<BufferIterator*>(&Cursor);
...
*const_cast<BufferIterator*>(&Cursor) = cur ...;

Aber das kann es doch nicht sein.

Doch, anders geht's nicht. Allerdings geht auch
const_cast<BufferIterator&>(Cursor)
und spart ein paar Sonderzeichen.

Nein, das klappt nicht. Offenbar wird auch dann nach einer Konvertierung
über Operatoren/Konstruktoren gesucht. (Vielleicht macht gcc 3.3.5 da
aber auch etwas falsch.)

In jedem Fall ist durch die cast meines Erachtens nicht mehr
sichergestellt, dass auch wirklich eine aktuelle Version des Iterators
verwendet wird. Da kann ich mir das volatile auch gleich sparen. Es mag
natürlich sein, dass viele Compiler es dennoch richtig machen ... heute!


Marcel

--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de

Back to top
Marcel Müller
Guest





PostPosted: Wed Dec 28, 2005 2:40 pm    Post subject: Re: volatile vector iterator will nicht Reply with quote

Torsten Robitzki wrote:
Quote:
"volatile" mag auf einer ganz bestimmten Platform, mit einem ganz
bestimmten Compiler den gewünschten Effekt erzeugen. Da du aber bereits
den "Plattformspezifischer Mutex-Semaphore-Wrapper" verwendest, solltest
Du Deine schwerr portable Verwendung von "volatile" überdenken Wink

Naja, schwer portabel hätte ich _das_ jetzt nicht genannt.

Ich glaube eher, dass volatile viel zu selten verwendet wird und es eher
ein Wunder ist, dass das en gros der Applikationen überhaupt
funktioniert. Genauer gesagt ist es natürlich kein Wunder, sondern mehr
ein Zeichen dafür, dass es kaum einen wirklich global optimierenden
Compiler gibt.

Vor einer Weile haben mich 4 gestandene Entwickler ziemlich komisch
angeguckt, als ich durch Einfügen von volatile einem Programm kurz und
schmerzlos auf die Sprünge geholfen habe. Die hatten das allesamt noch
nie gesehen, obwohl alle praktisch täglich mit Multithread-Applikationen
herummachen.

Soweit ich es verstanden habe, garantiert volatile, dass der Zugriff auf
ein Objekt auch wirklich innerhalb des aktuellen Synchronisationsblocks
erfolgt. Und das ist genau das, was man für Multithreading eigentlich
braucht.

Zitat aus der IBM C/C++ Referenz:
Quote:
The volatile qualifier maintains consistency in memory access to data objects.
Volatile objects are read from memory each time their value is needed,
and written
back to memory each time they are changed. The volatile qualifier is useful for
data objects having values that may be changed in ways unknown to your program
(such as the system clock). Objects referenced by multiple threads or by signal
handlers should also be qualified as volatile. Portions of an expression that
reference volatile objects are not to be changed or removed.

Das ist eigentlich ziemlich deutlich, oder. Bei anderen Compilern wird
man vmtl. ähnliches zu Lesen bekommen.


Marcel

--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de

Back to top
Torsten Robitzki
Guest





PostPosted: Wed Dec 28, 2005 4:58 pm    Post subject: Re: volatile vector iterator will nicht Reply with quote

Hallo Marcel,

Marcel Müller wrote:

Quote:
Torsten Robitzki wrote:

"volatile" mag auf einer ganz bestimmten Platform, mit einem ganz
bestimmten Compiler den gewünschten Effekt erzeugen. Da du aber
bereits den "Plattformspezifischer Mutex-Semaphore-Wrapper"
verwendest, solltest Du Deine schwerr portable Verwendung von
"volatile" überdenken ;-)


Naja, schwer portabel hätte ich _das_ jetzt nicht genannt.

Nun, auf der Platform, für die ich Software entwickel, würde das
volatile eine Optimierung wahrscheinlich auch verhindern. Bei der
Verwendung eines Mutex, ist es aber auch überflüssig und bremmst das
Programm unnötig aus.

Quote:
Ich glaube eher, dass volatile viel zu selten verwendet wird und es eher
ein Wunder ist, dass das en gros der Applikationen überhaupt
funktioniert. Genauer gesagt ist es natürlich kein Wunder, sondern mehr
ein Zeichen dafür, dass es kaum einen wirklich global optimierenden
Compiler gibt.

Ich gehe mal eher davon aus, das sobald Mehrprozessormaschinen üblicher
werden, es eine Menge Programme geben wird, die bis dato nur 'zufällig'
funktioniert haben ;-)

Quote:
Vor einer Weile haben mich 4 gestandene Entwickler ziemlich komisch
angeguckt, als ich durch Einfügen von volatile einem Programm kurz und
schmerzlos auf die Sprünge geholfen habe. Die hatten das allesamt noch
nie gesehen, obwohl alle praktisch täglich mit Multithread-Applikationen
herummachen.

Den selben Effekt hättest Du auch haben können, in dem Du via
Compilerschalter dem Compiler das Optimieren abgewöhnt hättest. Das es
dann funktioniert hätte, könnte dann auch den Schluß zulassen, das
multithreading nicht mit Optimierung zusammenpast Wink Mal ganz im Ernst,
da wird es eine race condition im Programm gegeben, die Du durch das
volatile verdeckt hast, bzw. behoben. Wobei letzteres wohl eher nicht
portable sein wird.

Quote:
Soweit ich es verstanden habe, garantiert volatile, dass der Zugriff auf
ein Objekt auch wirklich innerhalb des aktuellen Synchronisationsblocks
erfolgt. Und das ist genau das, was man für Multithreading eigentlich
braucht.

voltile ist für den Zugriff auf Hardwareregister, interrupts ect.
entworfen worden. Was es im Zusammenhang mit Multithreading bedeutet ist
compilerspezifisch.

Quote:
Zitat aus der IBM C/C++ Referenz:
Objects referenced by multiple threads or
by signal
handlers should also be qualified as volatile. Portions of an
expression that
reference volatile objects are not to be changed or removed.

Das ist eigentlich ziemlich deutlich, oder. Bei anderen Compilern wird
man vmtl. ähnliches zu Lesen bekommen.

Das macht ziemlich deutlich, was IBM davon hält. In der Tat habe ich
gerade in der OpenMP Dokumentation tatsächlich das Wort 'volatile'
gefunden. In anderen API Dokumentationen wir pthread oder Boost.Thread
wird es nicht erwähnt. Und diese APIs sind recht verbreitet.

Ich gebe Dir recht, das der Compiler keine Anweisungen um eine
Synchronisationsprmitive herum verschieben darf. Volatile ist dafür aber
meiner Meinung nach das falsche Mittel. API und Compiler müssen so auf
einander abgestimmt sein, das entweder der Compiler eh keine Anweisungen
um externe Funktionsaufrufe herum verschiebt, oder der Compiler muß
wissen, um welche Funktionsaufrufe er diese Verschiebungen eben nicht
machen darf.

Wenn Du in einem Codepfad, der nur von einem thread z.Z. durchlaufen
werden darf den Optimierer ausschaltest, erreichst Du genau das
Gegenteil von dem, was man eigentlich möchte: das der Thread so kurz wie
möglich in diesem Codepfad verweilt.

Wolltest Du alle verwendeten Objekte nur über Referenzen auf volatile
Objekte ändern, so müstest Du Dir die gesammte STL noch mal schreiben,
da die meisten Klassen dort keine volatile qualifizierten Funktionen
haben werden.

mfg Torsten

--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de

Back to top
Stefan Reuther
Guest





PostPosted: Wed Dec 28, 2005 8:03 pm    Post subject: Re: volatile vector iterator will nicht Reply with quote

Marcel Müller wrote:
Quote:
*const_cast<BufferIterator*>(&Cursor) = cur ...;

Doch, anders geht's nicht. Allerdings geht auch
const_cast<BufferIterator&>(Cursor)
und spart ein paar Sonderzeichen.

Nein, das klappt nicht. Offenbar wird auch dann nach einer Konvertierung
über Operatoren/Konstruktoren gesucht. (Vielleicht macht gcc 3.3.5 da
aber auch etwas falsch.)

Kann ich nicht nachvollziehen.

Quote:
royale:~ > /dos/c/mingw/bin/g++.exe -W -Wall -c vol.cpp
royale:~ > cat vol.cpp
#include <string

void modify(volatile std::string s)
{
const_cast }
royale:~ > /dos/c/mingw/bin/g++.exe --version
g++.exe (GCC) 3.4.2 (mingw-special)

bcc32 5.5.1 benimmt sich genauso.

Quote:
In jedem Fall ist durch die cast meines Erachtens nicht mehr
sichergestellt, dass auch wirklich eine aktuelle Version des Iterators
verwendet wird. Da kann ich mir das volatile auch gleich sparen. Es mag
natürlich sein, dass viele Compiler es dennoch richtig machen ... heute!

Eigentlich sollte es egal sein, ob du da einen Zeiger oder eine Referenz
castest. Ein Zeiger ist zugegebenermaßen 'expliziter'.


Stefan

--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de

Back to top
kanze
Guest





PostPosted: Thu Dec 29, 2005 3:13 pm    Post subject: Re: volatile vector iterator will nicht Reply with quote

Marcel Müller wrote:

Quote:
ich kämpfe gerade mit einer Multithread-Applikation.

Unter welchem Betriebssysteme. Es gibt eigentlich nichts
portable, worüber man was sagen kann.

Meine Kommentare unten sind auf der Posix-Norm basiert. Soweit
ich weiß behalten sich Linux und auch Windows ähnlich. Über
anderen Systemen weiß ich nichts.

Quote:
Sinngemäß:

class Buffer
{ typedef std::vector<char> BufferType;
typedef BufferType::iterator BufferIterator;

BufferType Buffer; // Ring-Buffer
Mutex BufferMutex; // Plattformspezifischer Mutex-Semaphore-Wrapper
volatile BufferIterator Cursor;

Wenn es nicht um Kernel Software oder Signal-Handler geht, hat
volatile hier nichts zu suchen.

In Allgemein, obwohl erlaubt, sehe ich überhaupt keine
Verwendung von volatile innerhalb einer Klasse. Auch in C würde
es nie in einer struct verwendet.

Quote:
public:
// Hole nächstes Stück Buffer, Maximallänge: len
Request(void*& data, size_t& len)
{ Lock(BufferMutex); // Hält die Semaphore, bis zum Lock-Destruktor
BufferIterator cur = Cursor; // hier geht der Ärger los!
size_t rem = Buffer.end() - cur; // Elemente noch im Buffer
if (rem < len)
len = rem;
data = &*cur;
cur += len;
Cursor = cur == Buffer.end() ? Buffer.begin() : cur; // neue Pos.
return;
}

Wenn alle anderen Zugriffe auf Cursor so geschützt sind, dann
ist das volatile überflüssig. Wenn nicht, reicht es weitgehend
nicht aus.

Laut der Posix-Norm. Laut der C++-Norm hast du undefiniertes
Verhalten, sofort du ein zweites Thread startest.

Quote:
...
};

Die Fehlermeldung ist sinngemäß, dass der Konstruktor
BufferIterator(volatile BufferIterator) nicht definiert ist.

Ist auch nicht erlaubt.

Quote:
Nach meinem Verständnis ist es üblich, dass die
volatile-Eigenschaft nicht automatisch mit kopiert wird. Bei
PODs und C-Style Pointern funktioniert das auch:

Ich weiß nicht genau, was du hier unter "kopiert" verstehst. Bei
der Zuweisung bzw. der Initialisierung eines POD findet sich
eine lvalue zu rvalue Umwandlung des zugewiesenen bzw. des
initialisierenden Wertes; lvalue zu rvalue Umwandlungen
verlieren grundsätzlich alle cv-qualifiers.

Ich denke, was du willst, ist BufferIterator::BufferIterator(
BufferIterator volatile& ). Was freilich nicht gibt.

Quote:
volatile int ri;
int li = ri;

char* volatile rp;
char* lp = rp;

Die STL-Iteratoren (in dem Fall die Implementation bei gcc)
verhalten sich aber offenbar nicht so.

Können nicht. rvalue von Klassentypen und von nicht
Klassentypen halten sich leicht anders.

Quote:
Ich habe mir jetzt mit folgendem, dreckigen Konstrukt mit dem
Umweg über einen Pointer beholfen:

BufferIterator cur = *const_cast ...
*const_cast<BufferIterator*>(&Cursor) = cur ...;

Aber das kann es doch nicht sein.

Außerdem wird dadurch m.E. das volatile-Attribut in seiner
Wirkung ausgeschaltet. Dieses ist aber erforderlich, damit
nicht irgend ein Optimizer auf die Idee kommt, den Wert von
WrPos über die Lock(BufferMutex) Anweisung hinweg zu cachen.

So ein Compiler wird dann nicht Posix-Konform. Und hat also
wahrscheinlich andere, großere Probleme, und darf überhaupt
nicht für Multithread-Anwendungen benutzt werden.

Quote:
(In der realen Anforderung läuft das Lock nicht über die
gesamte Funktion, sondern besteht aus zwei
aufeinanderfolgenden, synchronisierten Blöcken, in denen
jeweils auf Cursor zugegriffen wird.

Egal. Posix sagt ganz genau was du machen muß. Weniger
funktionniert nicht, und mehr ist überflüssig. Und volatile hat
nichts damit zu tun.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de

Back to top
kanze
Guest





PostPosted: Thu Dec 29, 2005 3:38 pm    Post subject: Re: volatile vector iterator will nicht Reply with quote

Torsten Robitzki wrote:

Quote:
Marcel Müller wrote:

Torsten Robitzki wrote:

"volatile" mag auf einer ganz bestimmten Platform, mit
einem ganz bestimmten Compiler den gewünschten Effekt
erzeugen. Da du aber bereits den "Plattformspezifischer
Mutex-Semaphore-Wrapper" verwendest, solltest Du Deine
schwerr portable Verwendung von "volatile" überdenken ;-)

Naja, schwer portabel hätte ich _das_ jetzt nicht genannt.

Nun, auf der Platform, für die ich Software entwickel, würde
das volatile eine Optimierung wahrscheinlich auch verhindern.
Bei der Verwendung eines Mutex, ist es aber auch überflüssig
und bremmst das Programm unnötig aus.

Auf den Platformen, auf denen ich arbeite, hat er dazu keine
andere Wirkung, als Optimierung zu verhindern. Was ihn beinahe
nutzlos macht. Auf für die Zwecke, wofür er ursprunglich gedacht
war.

Quote:
Ich glaube eher, dass volatile viel zu selten verwendet wird
und es eher ein Wunder ist, dass das en gros der
Applikationen überhaupt funktioniert. Genauer gesagt ist es
natürlich kein Wunder, sondern mehr ein Zeichen dafür, dass
es kaum einen wirklich global optimierenden Compiler gibt.

Ich gehe mal eher davon aus, das sobald Mehrprozessormaschinen
üblicher werden, es eine Menge Programme geben wird, die bis
dato nur 'zufällig' funktioniert haben Wink

Viel genauer: es gibt eine Menge Programme, die auch nicht auf
einfacheren Maschinen zuverlässig funktionnieren. Wenn der
Fehlerfall selten genug auftritt aber, merkt man es nicht
unbedingt.

Wenn man mit Mutex u.s.w. programmiert hat, dann wird mit
Mehrprozessormaschinen nichts ändern. Wenn man versucht hat,
Lock mittels volatile umzugehen, dagegen, werden neue Fehler
sichtbar werden.

Quote:
Vor einer Weile haben mich 4 gestandene Entwickler ziemlich
komisch angeguckt, als ich durch Einfügen von volatile einem
Programm kurz und schmerzlos auf die Sprünge geholfen habe.
Die hatten das allesamt noch nie gesehen, obwohl alle
praktisch täglich mit Multithread-Applikationen herummachen.

Den selben Effekt hättest Du auch haben können, in dem Du via
Compilerschalter dem Compiler das Optimieren abgewöhnt
hättest.

Wenn der Compiler Posix-konform ist, oder Windows-konform,
besteht keine Risiko wegen solchen Optimierungen. Wenn er es
nicht ist, funktionnieren auch wahrscheinlich nicht Exceptionen,
wenn zwei Threads eine gleiczeitig wirft. Entweder kennt der
Compiler seine Umgebung, und du kannst ihn ruhig benutzen, oder
er kennt sie nicht, und du kannst ihn gar nicht benutzen.

Quote:
Das es dann funktioniert hätte, könnte dann auch den
Schluß zulassen, das multithreading nicht mit Optimierung
zusammenpast Wink Mal ganz im Ernst, da wird es eine race
condition im Programm gegeben, die Du durch das volatile
verdeckt hast, bzw. behoben. Wobei letzteres wohl eher nicht
portable sein wird.

Soweit ich es verstanden habe, garantiert volatile, dass der
Zugriff auf ein Objekt auch wirklich innerhalb des aktuellen
Synchronisationsblocks erfolgt. Und das ist genau das, was
man für Multithreading eigentlich braucht.

voltile ist für den Zugriff auf Hardwareregister, interrupts
ect. entworfen worden. Was es im Zusammenhang mit
Multithreading bedeutet ist compilerspezifisch.

Es gibt mehr oder weniger portablen Standards, wie Posix.

Quote:
Zitat aus der IBM C/C++ Referenz:

Objects referenced by multiple threads or by signal
handlers should also be qualified as volatile. Portions of
an expression that reference volatile objects are not to be
changed or removed.

Das ist eigentlich ziemlich deutlich, oder. Bei anderen
Compilern wird man vmtl. ähnliches zu Lesen bekommen.

Das macht ziemlich deutlich, was IBM davon hält.

Ob er das aber eigentlich tut? Ich kenne den IBM Compiler nicht.
Ich kann aber sagen, dass weder Sun CC noch g++ noch VC++ tun
etwas besonders mit volatile, dass erlauben würde, dass es eine
Bedeutung bei Multithreading hat.

Ich verstehe nicht genau, was er mit volatile versucht. Warum
ist Cursor volatile, nicht aber Buffer, zum Beispiel? Beide
wurden in seiner Funktion angegriffen. Wenn volatile für eine
sinnvoll wäre, warum nicht für den anderen?

Quote:
In der Tat habe ich gerade in der OpenMP Dokumentation
tatsächlich das Wort 'volatile' gefunden. In anderen API
Dokumentationen wir pthread oder Boost.Thread wird es nicht
erwähnt. Und diese APIs sind recht verbreitet.

Pthread gehört zur Posix-Norm. Wenn Posix das Verhalten ohne
volatile garantiert, dann ist volatile überflüssig.

Quote:
Ich gebe Dir recht, das der Compiler keine Anweisungen um eine
Synchronisationsprmitive herum verschieben darf.

Stimmt eigentlich nicht. Laut Posix gibt es eine Primitiven, die
Speichersynchronisierung garantieren. Der Compiler ist also auch
gepflichtet, diese Garantie weiter zu leiten.

In den gängigen Fällen heute erfolgt das automatisch, indem der
Compiler die Speichersychronisierung über allen externe
Funktionnen garantiert. Intelligentere Compiler, die über den
Modulgrenzen hinausschauen, müssen halt pthread_lock u.s.w. als
Sonderfällen erkennen. (In der Praxis heute schauen auch solche
intelligenten Compiler nur in Modulen ein, deren Source-Code zur
verfügen steht. Was bei pthread_lock nicht der Fall ist.)

Quote:
Volatile ist dafür aber meiner Meinung nach das falsche
Mittel. API und Compiler müssen so auf einander abgestimmt
sein, das entweder der Compiler eh keine Anweisungen um
externe Funktionsaufrufe herum verschiebt, oder der Compiler
muß wissen, um welche Funktionsaufrufe er diese Verschiebungen
eben nicht machen darf.

Es geht nicht nur um deine Meinung hier. So sagt Posix.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de

Back to top
Marcel Müller
Guest





PostPosted: Mon Jan 02, 2006 9:18 pm    Post subject: Re: volatile vector iterator will nicht Reply with quote

Hallo!

kanze wrote:
Quote:
Marcel Müller wrote:

ich kämpfe gerade mit einer Multithread-Applikation.

Unter welchem Betriebssysteme. Es gibt eigentlich nichts
portable, worüber man was sagen kann.

Meine Kommentare unten sind auf der Posix-Norm basiert. Soweit
ich weiß behalten sich Linux und auch Windows ähnlich. Über
anderen Systemen weiß ich nichts.

In dem Fall ist es OS/2, derzeit mit gcc 3.3.5. Das verhält sich zu 70%
wie Windows und zu 20% wie Unix und der Rest ist halt anders.
Posix-Konform ist es jedenfalls nur bedingt.
Einen Linux-Port werde ich aber vmtl. auch noch machen.


Quote:
Wenn es nicht um Kernel Software oder Signal-Handler geht, hat
volatile hier nichts zu suchen.

In Allgemein, obwohl erlaubt, sehe ich überhaupt keine
Verwendung von volatile innerhalb einer Klasse. Auch in C würde
es nie in einer struct verwendet.
[Mutex]
Wenn alle anderen Zugriffe auf Cursor so geschützt sind, dann
ist das volatile überflüssig. Wenn nicht, reicht es weitgehend
nicht aus.

Voraussetzung ist, dass der Compiler weiss, dass die Funktion Lock() und
~Lock() eine Speichersynchronisation erfordern. Wenn ich das dem
Compiler nicht mitteilen kann (und ich wüsste nicht wie), ist eine
Änderung des Wertes in einem Hardwareregister mit der Änderung durch
einen anderen Thread durchaus gleichzusetzen.


Quote:
Laut der Posix-Norm. Laut der C++-Norm hast du undefiniertes
Verhalten, sofort du ein zweites Thread startest.

Genau Letzteres scheint das Problem. Die C++-Norm hinkt da etwas
hinterher. Ich habe in den letzten Jahren nur noch wenige
Single-Thread-Anwendungen in C++ benötigt. Bei einfachen Dingen lande
ich oft eher bei einer Skriptsprache, wie Perl.


Quote:
Ich weiß nicht genau, was du hier unter "kopiert" verstehst. Bei
der Zuweisung bzw. der Initialisierung eines POD findet sich
eine lvalue zu rvalue Umwandlung des zugewiesenen bzw. des
initialisierenden Wertes; lvalue zu rvalue Umwandlungen
verlieren grundsätzlich alle cv-qualifiers.

Exakt das.

[const_cast]
Quote:
Außerdem wird dadurch m.E. das volatile-Attribut in seiner
Wirkung ausgeschaltet. Dieses ist aber erforderlich, damit
nicht irgend ein Optimizer auf die Idee kommt, den Wert von
WrPos über die Lock(BufferMutex) Anweisung hinweg zu cachen.

So ein Compiler wird dann nicht Posix-Konform. Und hat also
wahrscheinlich andere, großere Probleme, und darf überhaupt
nicht für Multithread-Anwendungen benutzt werden.

Es würde mich schwer wundern, wenn jeder im obigen Kontext benutzbare
Compiler bei jedem Funktionsaufruf eine Speichersynchronisation
garantieren würde. Vor allem im Kontext der bei C++ sehr weit
verbreiteten trivialen Inline-Funktionen wäre das selbstmord. CPU mit
langen Pipelines würden mangels wirksamen Instruction-Scheduling ja
nahezu stehen bleiben, wenn der Compiler. Spätestens bei der
automatischen Inline-Expansion, die manche Compiler bieten, wird es
endgültig fragwürdig.

Vielleicht habe ich aber auch das Verfahren, über das diese Garantie
realisiert wird, einfach nicht verstanden. Aber selbst, wenn der
Compiler nur bei realen CALL-Aufrufen synchronisiert, was auf den ersten
Blick reichen würde, kommt er spätestens bei Lesezugriffen im
klassischen Double-Check Stil ins straucheln. Die sehen etwa so aus:

Aufgabe: lese den Wert von i und setzte in atomar auf 0.
(In Intel-Assembler könnte man für das einfache Beispiel natürlich ein
LOCK XCHG nehmen, aber das hilft nicht im allgemeinen Fall.)

int i;
Mutex i_mutex;

int ReadAndReset_i()
{ if (i == 0)
{ return 0;
} else
{ Lock(i_mutex);
int r = i;
i = 0;
return r;
}
}

Das ist gängige Praxis und kann ein Programm um Größenordungen
beschleunigen, falls i in den allermeisten Fällen 0 ist, da nahezu 100%
der Semaphoren-Zugriffe eliminiert werden. Das funktioniert sogar auf
Multiprozessormaschinen und auf solchen, bei denen die Zuweisung von i
(selbstverständlich durch i_mutex geschützt) keine implizit atomare
Instruktion ist. In dem Fall wäre eine Inline-Expansion der Funktion mit
einem möglichen Cachen des Wertes von i in einem Prozessorregister
Fatal, oder würde in diesem Fall zumindest die Wirksamkeit dieser
Optimierung in Frage stellen.


Quote:
Egal. Posix sagt ganz genau was du machen muß. Weniger
funktionniert nicht, und mehr ist überflüssig. Und volatile hat
nichts damit zu tun.

Fakt ist es funktioniert seit ein paar Tagen - ohne volatile. Ob Zufall
oder nicht, das werden wir möglicherweise nie erfahren.


Marcel

--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de

Back to top
Torsten Robitzki
Guest





PostPosted: Mon Jan 02, 2006 10:13 pm    Post subject: Re: volatile vector iterator will nicht Reply with quote

Marcel Müller wrote:

Quote:
Aufgabe: lese den Wert von i und setzte in atomar auf 0.
(In Intel-Assembler könnte man für das einfache Beispiel natürlich ein
LOCK XCHG nehmen, aber das hilft nicht im allgemeinen Fall.)

int i;
Mutex i_mutex;

int ReadAndReset_i()
{ if (i == 0)
{ return 0;
} else
{ Lock(i_mutex);
int r = i;
i = 0;
return r;
}
}

Das ist gängige Praxis

Ich würde sagen das 'war' vor 5 Jahren so. Tatsache ist, das es
Platformen wie z.B. Alpha oder Itanium gibt, bei denen die Hardware
hinter der CPU die Reihenfolge von Schreiboperationen in den Speicher
umsortieren kann. In Deinem Beispiel könnte dann eine andere CPU die
Zuweisung "i = 0" sehen, bevor sie die Änderung von r sieht.

Quote:
und kann ein Programm um Größenordungen
beschleunigen, falls i in den allermeisten Fällen 0 ist, da nahezu 100%
der Semaphoren-Zugriffe eliminiert werden. Das funktioniert sogar auf
Multiprozessormaschinen und auf solchen, bei denen die Zuweisung von i
(selbstverständlich durch i_mutex geschützt) keine implizit atomare
Instruktion ist.

Das ganze hat eigentlich wenig mit ein, zwei oder n Prozessoren, noch
mit irgend welchen Betriebssystemen zu tun. Das einzig zuverlässige z.Z.
ist die Dokumentation Deines Compilers. OS2 wird sicherlich auch posix
threads unterstützen und damit wären auch ein "nur" lesender Zugriff auf
i erst gesichert möglich, wenn der gleiche Mutex gehalten wird, der auch
beim Schreiben auf i gehalten wird. Für Dein konkretes Problem, hat
posix mit once Variablen eine Lösung.

Quote:
In dem Fall wäre eine Inline-Expansion der Funktion mit
einem möglichen Cachen des Wertes von i in einem Prozessorregister
Fatal, oder würde in diesem Fall zumindest die Wirksamkeit dieser
Optimierung in Frage stellen.

S.o. warum denkst Du, das das was Du da geschrieben hast funktioniert?
Gerade das Initialisieren von irgend welchen Singletons am Anfang des
Programms werden nur selten schief gehen, selbst ohne oder mit
fehlerhafter Synchronisation.

<snip>
Quote:
Fakt ist es funktioniert seit ein paar Tagen - ohne volatile. Ob Zufall
oder nicht, das werden wir möglicherweise nie erfahren.

Das sollte kein Zufall sein, sondern in der Dokumentation Deines
Compilers stehen ;-)

mfg Torsten

--
de.comp.lang.iso-c++ - Moderation: mailto:voyager+mod (AT) bud (DOT) prima.de
FAQ: http://www.voyager.prima.de/cpp/ mailto:voyager+send-faq (AT) bud (DOT) prima.de

Back to top
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (German) All times are GMT
Page 1 of 1

 
 


Powered by phpBB © 2001, 2006 phpBB Group