Frage

Ich war kommentieren auf eine Antwort diesem Thread-lokalen Speicher ist schön und erinnerte an eine andere informative Diskussion über Ausnahmen, bei denen ich annehmen

  

Das einzige Besondere an der   Ausführungsumgebung innerhalb des throw   Block ist, dass das Ausnahmeobjekt ist   verwiesen durch rethrow.

Setzen von zwei und zwei zusammen, würde nicht eine gesamte Faden innerhalb einer Funktion-catch-Block von seiner Hauptfunktion Imbue mit gewinde lokalen Speicher ausführt?

Es scheint gut zu funktionieren, wenn auch langsam. Ist das neue oder gut charakterisierte? Gibt es eine andere Möglichkeit, das Problem zu lösen? War meine erste Prämisse richtig? Welche Art von Overhead tut get_thread incur auf Ihrer Plattform? Was ist das Optimierungspotenzial?

#include <iostream>
#include <pthread.h>
using namespace std;

struct thlocal {
    string name;
    thlocal( string const &n ) : name(n) {}
};

struct thread_exception_base {
    thlocal &th;
    thread_exception_base( thlocal &in_th ) : th( in_th ) {}
    thread_exception_base( thread_exception_base const &in ) : th( in.th ) {}
};

thlocal &get_thread() throw() {
    try {
        throw;
    } catch( thread_exception_base &local ) {
        return local.th;
    }
}

void print_thread() {
    cerr << get_thread().name << endl;
}

void *kid( void *local_v ) try {
    thlocal &local = * static_cast< thlocal * >( local_v );
    throw thread_exception_base( local );
} catch( thread_exception_base & ) {
    print_thread();

    return NULL;
}

int main() {
    thlocal local( "main" );
    try {
        throw thread_exception_base( local );
    } catch( thread_exception_base & ) {
        print_thread();

        pthread_t th;
        thlocal kid_local( "kid" );
        pthread_create( &th, NULL, &kid, &kid_local );
        pthread_join( th, NULL );

        print_thread();
    }

    return 0;
}

Dies erfordert neue Ausnahmeklassen definiert, von thread_exception_base abgeleitet, die Basis mit get_thread() initialisiert, aber insgesamt das fühlt sich nicht wie eine unproduktive Schlaflosigkeit geplagten Sonntagmorgen ...

EDIT: Sieht aus wie GCC macht drei Anrufe pthread_getspecific in get_thread. EDIT: und viele böse Innerlichkeit in den Stapel, Umwelt und ausführbare Format des catch Block I auf dem ersten Durchlauf verpasst zu finden. Das sieht sehr plattformabhängig, wie GCC einige libunwind aus dem O ruft. Overhead in der Größenordnung von 4000 Zyklen. Ich nehme an, es muss auch die Klassenhierarchie durchlaufen, aber das kann unter Kontrolle gehalten werden.

War es hilfreich?

Lösung

Im spielerischen Geist der Frage, biete ich diese schreckliche Alptraum Schöpfung:

class tls
{
    void push(void *ptr)
    {
        // allocate a string to store the hex ptr 
        // and the hex of its own address
        char *str = new char[100];
        sprintf(str, " |%x|%x", ptr, str);
        strtok(str, "|");
    }

    template <class Ptr>
    Ptr *next()
    {
        // retrieve the next pointer token
        return reinterpret_cast<Ptr *>(strtoul(strtok(0, "|"), 0, 16));
    }

    void *pop()
    {
        // retrieve (and forget) a previously stored pointer
        void *ptr = next<void>();
        delete[] next<char>();
        return ptr;
    }

    // private constructor/destructor
    tls() { push(0); }
    ~tls() { pop(); }

public:
    static tls &singleton()
    {
        static tls i;
        return i;
    }

    void *set(void *ptr)
    {
        void *old = pop();
        push(ptr);
        return old;
    }

    void *get()
    {
        // forget and restore on each access
        void *ptr = pop();
        push(ptr);
        return ptr;
    }
};

Vorteil der Tatsache, dass nach dem C ++ Standard, strtok stashes erstes Argument, so dass nachfolgende Aufrufe 0 passieren können weitere Token aus der gleichen Zeichenfolge abzurufen, so deshalb in einem Thread-aware Implementierung es TLS verwenden müssen.

example *e = new example;

tls::singleton().set(e);

example *e2 = reinterpret_cast<example *>(tls::singleton().get());

Also, solange strtok nicht in die vorgesehenen Art und Weise verwendet wird, irgendwo anders im Programm haben wir eine weiteren Ersatz TLS-Steckplatz.

Andere Tipps

Ich glaube, Sie auf etwas sind hier. Dies könnte auch eine tragbare Art und Weise sein, Daten in Rückrufe zu erhalten, die nicht über einen Benutzer „Zustand“ Variable akzeptieren, wie Sie erwähnt haben, auch abgesehen von jeder expliziten Verwendung von Threads.

So klingt es wie Sie die Frage in Ihrem Thema beantwortet haben. YES

void *kid( void *local_v ) try {
    thlocal &local = * static_cast< thlocal * >( local_v );
    throw local;
} catch( thlocal & ) {
    print_thread();

    return NULL;
}

==

void *kid (void *local_v ) { print_thread(local_v); }

Ich könnte hier etwas fehlt, aber es ist kein Thread-Lokalspeicher, nur unnötig kompliziert Argument. Argument ist für jeden Thread nur, weil es zu pthread_create geführt wird, nicht wegen irgendeiner Ausnahme Jonglieren.


Es stellte sich heraus, dass ich in der Tat fehlte, dass GCC tatsächlichen lokalen Threadspeicher Anrufe in diesem Beispiel produziert. Es macht tatsächlich die Frage interessant. Ich bin noch nicht ganz sicher, ob es ein Fall für andere Compiler ist und wie unterscheidet es sich von Aufruf Fadenspeicher direkt an.

Ich stehe nach wie vor durch mein allgemeines Argument, dass die gleichen Daten in einer einfacheren und geradlinig Art und Weise zugegriffen werden können, wäre es Argumente, Stapel zu Fuß oder Gewinde lokale Speicher.

Daten über den aktuellen Funktion Call-Stack Zugriff wird immer Thread-sicher. Deshalb Code Thread-sicher ist, nicht wegen des geschickten Einsatzes von Ausnahmen. Fädeln lokalen Speicher ermöglicht es uns, Speicher pro Thread Daten und verweisen sie außerhalb des unmittelbaren Call-Stack.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top