UClibc-Daemon und pthread_create, die in eingebettetes Linux passen

Überblick

uClibc ist ein Standard-C, das am besten für Linux-Umgebungen mit begrenzter Hardware wie Ressourcen geeignet ist, wie Sie vielleicht wissen, wenn Sie sich mit der Entwicklung eingebetteter Linux beschäftigen. Es ist eine Bibliothek. Unter normalem PC Linux werden Bibliotheken wie "glibc" verwendet, aber in verschiedenen Umgebungen werden solche leichtgewichtigen Bibliotheken verwendet.

Übrigens denke ich, dass Multithread und Multiprozess vorsichtig sind, weil sie beim Mischen gefährlich riechen. Wenn Sie jedoch aufmerksam sind und einfach versuchen, einen Daemon für eine Multithread-Implementierung zu erstellen, geraten Sie in eine Falle.

Bitte beachten Sie, dass die unten beschriebenen Fälle in "uClibc" und wahrscheinlich nicht auf dem oben genannten PC Linux zu finden sind. Es kann auch nur eine ältere Version sein.

Phänomen

Siehe den folgenden Code:

thread_test.c


#include <stdio.h>
#include <stdlib.h>

#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>


void* do_something( void *object )
{
    size_t i;

    for ( i = 0; i < 5; ++i )
    {
        printf(
            "Hello, this is another thread! "
            "( times = %zd, tid = %p )\n",

            i,
            ( void * ) pthread_self()
        );
        sleep( 2 );
    }

    return NULL;
}


int main()
{
    size_t    i;
    pthread_t thread;

    printf( "New thread will be created. ( tid = %p )\n", ( void * ) pthread_self() );
    pthread_create( &thread, NULL, do_something, NULL );

    for ( i = 0; i < 10; ++i )
    {
        printf( "The old thread keeps going on... ( tid = %p )\n", ( void * ) pthread_self() );
        sleep( 1 );
    }

    pthread_join( thread, NULL );
    printf( "threads are joined.\n" );

    return 0;
}

Dieser Code ist ein gängiges Beispiel für Multithreading, bei dem der Hauptthread die Nachricht zehnmal anzeigt, während die Funktion "do_something" in einem anderen Thread ausgeführt wird und die Nachricht fünfmal angezeigt wird. Schließlich enden die beiden Threads mit pthread_join.

Wie Sie sich vorstellen können, sieht die Ausgabe folgendermaßen aus:

stdout


New thread will be created. ( tid = 0x1111 )
The old thread keeps going on... ( tid = 0x1111 )          
Hello, this is another thread! ( times = 0, tid = 0x1234 )
The old thread keeps going on... ( tid = 0x1111 )
The old thread keeps going on... ( tid = 0x1111 )
Hello, this is another thread! ( times = 1, tid = 0x1234 )
The old thread keeps going on... ( tid = 0x1111 )
Hello, this is another thread! ( times = 2, tid = 0x1234 )
The old thread keeps going on... ( tid = 0x1111 )
The old thread keeps going on... ( tid = 0x1111 )
Hello, this is another thread! ( times = 3, tid = 0x1234 )
The old thread keeps going on... ( tid = 0x1111 )
The old thread keeps going on... ( tid = 0x1111 )
Hello, this is another thread! ( times = 4, tid = 0x1234 )
The old thread keeps going on... ( tid = 0x1111 )
The old thread keeps going on... ( tid = 0x1111 )
threads are joined.

(Der Vorgang ist abgeschlossen)

Jetzt möchte ich diesen Prozess als Daemon im Hintergrund ausführen, daher ist er salzig und praktisch, daemon () (http://linuxjm.osdn.jp/html/LDP_man-pages/man3/daemon.3). Rufen Sie html) an und bitten Sie sie, zu deseamonisieren.

daemonized_thread.c


int main()
{
    size_t    i;
    pthread_t thread;

    // process should be daemonized here!
    if ( daemon( 1, 1 ) )
    {
        fprintf( stderr, "daemonization failed." );
        exit( 1 );
    }

    printf( "New thread will be created. ( tid = %p )\n", ( void * ) pthread_self() );
    pthread_create( &thread, NULL, do_something, NULL );

    for ( i = 0; i < 10; ++i )
    {
        printf( "The old thread keeps going on... ( tid = %p )\n", ( void * ) pthread_self() );
        sleep( 1 );
    }

    pthread_join( thread, NULL );
    printf( "threads are joined.\n" );

    return 0;
}

Was ist dann mit der Ausgabe, die so aussieht und niemals endet:

stdout


New thread will be created. ( tid = 0x1111 )
Hello, this is another thread! ( times = 0, tid = 0x1234 )
Hello, this is another thread! ( times = 1, tid = 0x1234 )
Hello, this is another thread! ( times = 2, tid = 0x1234 )
Hello, this is another thread! ( times = 3, tid = 0x1234 )
Hello, this is another thread! ( times = 4, tid = 0x1234 )
(Der Prozess endet nicht)

Anscheinend blieb der Haupt-Thread um pthread_create () hängen und steckte fest.

Was ist los

Eine Suche nach "uClibc pthread daemon" scheint ziemlich problematisch zu sein und bringt Informationen zum Forum und zur Mailingliste:

Gemäß den Informationen in der Mailingliste unten ist die Ursache des Problems, dass "fork ()", das in "daemon ()" aufgerufen wird, das interne Symbol "fork ()" anstelle von "fork ()" in "libpthread" aufruft. Dies scheint darauf zurückzuführen zu sein, dass der Thread-Manager von "pthread" die PID des Haupt-Threads nach "fork ()" verliert (das ist es).

Die Lösung hierfür besteht darin, einen ähnlichen daemon () - Prozess selbst zu implementieren, wie z. B. die fork () des pthread: https://dev.openwrt.org/browser/trunk/package/fuse/patches/300-workaround-uclibc-pthread-breakage.patch?rev=13312

Das Ganze mit der Lösung

daemonized_thread_fixed.c


#include <stdio.h>
#include <stdlib.h>

#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>


int my_daemon( int nochdir, int noclose )
{
    int res;
    int fd;

    switch ( res = fork() )
    {
        case -1:
            return 1;

        case 0:
            break;

        default:
            exit( 0 );
    }

    if ( ( res = setsid() ) == -1 )
    {
        return 1;
    }

    if ( !nochdir )
    {
        chdir( "/" );
    }

    if ( !noclose && ( fd = open( "/dev/null", O_RDWR, 0 ) ) != -1 )
    {
        dup2( fd, STDIN_FILENO );
        dup2( fd, STDOUT_FILENO );
        dup2( fd, STDERR_FILENO );

        if ( fd > 2 )
        {
            close( fd );
        }
    }

    return 0;
}


void* do_something( void *object )
{
    size_t i;

    for ( i = 0; i < 5; ++i )
    {
        printf(
            "Hello, this is another thread! "
            "( times = %zd, tid = %p )\n",

            i,
            ( void * ) pthread_self()
        );
        sleep( 2 );
    }

    return NULL;
}


int main()
{
    size_t    i;
    pthread_t thread;

    if ( my_daemon( 1, 1 ) )
    {
        fprintf( stderr, "daemonization failed." );
        exit( 1 );
    }

    printf( "New thread will be created. ( tid = %p )\n", ( void * ) pthread_self() );
    pthread_create( &thread, NULL, do_something, NULL );

    for ( i = 0; i < 10; ++i )
    {
        printf( "The old thread keeps going on... ( tid = %p )\n", ( void * ) pthread_self() );
        sleep( 1 );
    }

    pthread_join( thread, NULL );
    printf( "threads are joined.\n" );

    return 0;
}

Anscheinend hat das funktioniert. Ich bin glücklich.

Recommended Posts

UClibc-Daemon und pthread_create, die in eingebettetes Linux passen
Setzen Sie Linux in Chromebook ein und verwenden Sie R ...
Werkzeuge, die in Ihre Hand passen (Programmiersprache)
Eine App, die Sie in Linux einfügen müssen