2016-04-26 8 views
3

In Glibc der pthread.h der pthread_self Funktion wird mit dem const Attribut deklariert:Warum Pthread_self ist mit Attribut (const) markiert?

extern pthread_t pthread_self (void) __THROW __attribute__ ((__const__)); 

In GCC that attribute means:

Viele Funktionen untersuchen keine Werte außer ihre Argumente und haben keine Auswirkungen, außer der Rückkehr Wert. Im Grunde genommen ist dies nur eine geringfügig strengere Klasse als das unten stehende pure-Attribut, da es der Funktion nicht erlaubt ist, globalen Speicher zu lesen.

Ich frage mich, wie das sein soll? Da es kein Argument braucht, pthread_self ist daher nur erlaubt immer den gleichen Wert, was offensichtlich nicht der Fall ist. Das heißt, würde ich pthread_self erwartete globale Speicher zu lesen, und deshalb schließlich als pure stattdessen markiert werden:

Viele Funktionen haben keine Auswirkungen außer dem Rückgabewert und dessen Rückgabewert hängt nur von den Parametern und/oder global Variablen. Eine solche Funktion kann einer gemeinsamen Teilausdruckseliminierung und Schleifenoptimierung unterzogen werden, genau wie es ein arithmetischer Operator wäre. Diese Funktionen sollten mit dem Attribut pure deklariert werden.

Die Implementierung kann auf x86-64 scheint tatsächlich zu lesen globale Speicher zu sein:

# define THREAD_SELF \ 
    ({ struct pthread *__self;           \ 
    asm ("mov %%fs:%c1,%0" : "=r" (__self)       \ 
      : "i" (offsetof (struct pthread, header.self)));    \ 
    __self;}) 

pthread_t 
__pthread_self (void) 
{ 
    return (pthread_t) THREAD_SELF; 
} 
strong_alias (__pthread_self, pthread_self) 

Ist das ein Bug oder bin ich nicht etwas zu sehen?

+2

Es gibt immer den gleichen Wert * in einem bestimmten Thread *. Wenn Sie eine reine Funktion aufrufen, eine globale Variable ändern und dann erneut aufrufen, erhalten Sie möglicherweise einen anderen Rückgabewert. Wenn Sie keine globale Variable dazwischen ändern und die Parameter identisch sind, kann der Compiler davon ausgehen, dass der Rückgabewert derselbe ist. Dies kann nicht mit einer '__const__'-Funktion wie' pthread_self() 'geschehen, weil der Rückgabewert nicht vom Wert globaler Variablen abhängt. Die Tatsache, dass es einen anderen Wert in einem anderen Thread zurückgibt, ist für das, was hier passiert, nicht wirklich relevant. –

+1

Dieser Speicher ist nicht wirklich global, sondern ist im '% fs'-Segment ein spezielles Segment, das normalerweise lokalen Thread-Speichern gewidmet ist. Es greift also tatsächlich auf lokalen Thread-Speicher zu. – rodrigo

+0

@PaulGriffiths: IOW gibt es Wechselwirkungen mit 'pure'-ness und' const'-ness und Multithreading. Schön genug, aber das erklärt nicht, wie 'pthread_self' implementiert werden kann, ohne sogar irgendeinen globalen Speicher zu lesen? – peppe

Antwort

1

Ich frage mich, wie das sein soll?

Dieses Attribut sagt dem Compiler, dass in einem bestimmten Kontextpthread_self immer den gleichen Wert zurück. Mit anderen Worten sind die beiden Schleifen unter genau gleichwertig, und der Compiler erlaubt ist, die zweite zu optimieren (und alle nachfolgenden) ruft pthread_self:

// loop A 
std::map<pthread_t, int> m; 
for (int j = 0; j < 1000; ++j) 
    m[pthread_self()] += 1; 

// loop B 
std::map<pthread_t, int> m; 
const pthread_t self = pthread_self(); 
for (int j = 0; j < 1000; ++j) 
    m[self] += 1; 

Die Implementierung kann auf x86-64 tatsächlich zu sein scheint Lesen des globalen Speichers

Nein, tut es nicht. Es liest Thread-lokalen Speicher.

+0

Ich weiß, dass das der ultimative Zweck der "const" - und "pure" -Attribute ist, aber dies wiederum erklärt nicht ganz, warum 'const' und nicht' pure'. ... ist die Dokumentation über diese Semantik einfach falsch? Kann 'f' in' const char array [] = "Hallo, Welt!"; char f (int i) {Rückgabearray [i]; } 'als' const' oder 'pure' markiert sein? Die Dokumentation sagt "rein", jeder hier sagt "const". – peppe

3

Das Attribut wurde höchstwahrscheinlich in der Annahme hinzugefügt, dass GCC es nur lokal (innerhalb einer Funktion) verwenden würde und es nie für interprozessuale Optimierungen verwenden könnte. Heute stellen einige Glibc-Entwickler die Korrektheit des Attributs in Frage, und zwar genau deshalb, weil eine leistungsfähige interprozedurale Optimierung möglicherweise zu einer Fehlkompilierung führen könnte. post by Torvald Riegel to Glibc developers' mailing list zitiert,

const Das Attribut wird als behauptet spezifiziert, daß die Funktion nicht irgendwelche Daten außer den Argumenten untersuchen. __errno_location hat keine Argumente, also müsste es immer die gleichen Werte jedes Mal zurückgeben. Dies funktioniert in einem single-threaded Programm, aber nicht in einem multi-threaded . Daher denke ich, dass es genau genommen nicht const sein sollte.

Wir könnten argumentieren, dass dies magisch immer im Kontext eines bestimmten Threads sein soll. Ignorieren, dass GCC nicht Threads selbst (vor allem in etwas wie NPTL, die über ein Erstellen von Threads ist) definieren, könnten wir immer noch davon ausgehen, dass dies funktioniert, weil in der Praxis der Compiler und seine Pässe nicht wissen können Eine Funktion, die in einen Thread verwendet und andere in einem anderen Thread verwendet.

(__errno_location() und pthread_self() beide mit __attribute__((const)) markiert und keine Argumente erhalten).

Hier ist ein kleines Beispiel, das plausibel mit leistungsstarker interprozedurales Analyse miscompiled werden:

#include <pthread.h> 
#include <errno.h> 
#include <stdlib.h> 

static void *errno_pointer; 

static void *thr(void *unused) 
{ 
    if (!errno_pointer || errno_pointer == &errno) 
    abort(); 
    return 0; 
} 

int main() 
{ 
    errno_pointer = &errno; 
    pthread_t t; 
    pthread_create(&t, 0, thr, 0); 
    pthread_join(t, 0); 
} 

(die Compiler beobachten können, dass errno_pointer statisch ist, ist es nicht die Übersetzungseinheit, und in sich den einzigen Laden weist entkommt der gleiche "const" -Wert, gegeben durch __errno_location(), der in thr() getestet wird). Ich habe dieses Beispiel in my email asking to improve documentation of pure/const attributes verwendet, aber leider hat es nicht viel Traktion bekommen.

+0

Danke für die aufschlussreiche Antwort (und die Links), dies bestätigt mir, dass die Dokumentation für "const" und "pure" in einer Multithreadumgebung absolut nicht klar ist ... – peppe

Verwandte Themen