Heim  >  Artikel  >  Betrieb und Instandhaltung  >  Beispielcode-Analyse für Linux-Multithread-Programmierung

Beispielcode-Analyse für Linux-Multithread-Programmierung

王林
王林nach vorne
2023-05-26 22:04:041534Durchsuche

Nehmen wir zunächst ein Beispiel. Wir erstellen zwei Threads, um eine Zahl zu erhöhen. Vielleicht hat dieses Beispiel keinen praktischen Wert, aber mit einer kleinen Änderung können wir es an anderen Stellen verwenden.

Code:

/*thread_example.c : c multiple thread programming in linux
 *author : falcon
 *e-mail : tunzhj03@st.lzu.edu.cn
 */
#include <pthread.h>
#include <stdio.h>
#include <sys/time.h>
#include <string.h>
#define max 10

pthread_t thread[2];
pthread_mutex_t mut;
int number=0, i;

void *thread1()
{
    printf ("thread1 : i&#39;m thread 1/n");

    for (i = 0; i < max; i++)
    {
        printf("thread1 : number = %d/n",number);
        pthread_mutex_lock(&mut);
            number++;
        pthread_mutex_unlock(&mut);
        sleep(2);
    }


    printf("thread1 :主函数在等我完成任务吗?/n");
    pthread_exit(null);
}

void *thread2()
{
    printf("thread2 : i&#39;m thread 2/n");

    for (i = 0; i < max; i++)
    {
        printf("thread2 : number = %d/n",number);
        pthread_mutex_lock(&mut);
            number++;
        pthread_mutex_unlock(&mut);
        sleep(3);
    }


    printf("thread2 :主函数在等我完成任务吗?/n");
    pthread_exit(null);
}

void thread_create(void)
{
    int temp;
    memset(&thread, 0, sizeof(thread));     //comment1
    /*创建线程*/
    if((temp = pthread_create(&thread[0], null, thread1, null)) != 0) //comment2   
        printf("线程1创建失败!/n");
    else
        printf("线程1被创建/n");

    if((temp = pthread_create(&thread[1], null, thread2, null)) != 0) //comment3
        printf("线程2创建失败");
    else
        printf("线程2被创建/n");
}

void thread_wait(void)
{
    /*等待线程结束*/
    if(thread[0] !=0)      {       //comment4          pthread_join(thread[0],null);
        printf("线程1已经结束/n");
     }
    if(thread[1] !=0)      {         //comment5        pthread_join(thread[1],null);
        printf("线程2已经结束/n");
     }
}

int main()
{
    /*用默认属性初始化互斥锁*/
    pthread_mutex_init(&mut,null);

    printf("我是主函数哦,我正在创建线程,呵呵/n");
    thread_create();
    printf("我是主函数哦,我正在等待线程完成任务阿,呵呵/n");
    thread_wait();

    return 0;
}

Lass es uns zuerst kompilieren und ausführen

Zitat:

falcon@falcon:~/program/c/code/ftp$ gcc -lpthread -o thread_example thread_example.c
falcon@falcon:~/program/c/code/ftp$ ./thread_example
我是主函数哦,我正在创建线程,呵呵
线程1被创建
线程2被创建
我是主函数哦,我正在等待线程完成任务阿,呵呵
thread1 : i&#39;m thread 1
thread1 : number = 0
thread2 : i&#39;m thread 2
thread2 : number = 1
thread1 : number = 2
thread2 : number = 3
thread1 : number = 4
thread2 : number = 5
thread1 : number = 6
thread1 : number = 7
thread2 : number = 8
thread1 : number = 9
thread2 : number = 10
thread1 :主函数在等我完成任务吗?
线程1已经结束
thread2 :主函数在等我完成任务吗?
线程2已经结束

Die Kommentare im Beispielcode sollten jetzt klarer sein.

Zitat:

Thread-bezogene Vorgänge

一 pthread_t

pthread_t ist in der Header-Datei /usr/include/bits/pthreadtypes.h definiert:
 typedef unsigned long int pthread_t;
 Es ist die Kennung eines Threads.

Zweiter pthread_create

Die Funktion pthread_create wird zum Erstellen eines Threads verwendet. Sein Prototyp ist:
 extern int pthread_create __p ((pthread_t *__thread, __const pthread_attr_t *__attr,
 void *(*__start_routine) (void *), void * __arg ));
Der erste Parameter ist ein Zeiger auf die Thread-ID, der zweite Parameter wird zum Festlegen der Thread-Attribute verwendet, der dritte Parameter ist die Startadresse der Thread-Ausführungsfunktion und der letzte Parameter ist der Parameter der Ausführung Funktion. Hier benötigt unser Funktionsthread keine Parameter, daher wird der letzte Parameter auf einen Nullzeiger gesetzt. Wir setzen außerdem den zweiten Parameter auf einen Nullzeiger, wodurch ein Thread mit Standardattributen generiert wird. Das Setzen und Ändern von Thread-Attributen erklären wir im nächsten Abschnitt. Wenn der Thread erfolgreich erstellt wurde, gibt die Funktion 0 zurück. Wenn er nicht 0 ist, schlägt die Thread-Erstellung fehl. Häufige Fehlerrückgabecodes sind eagain und einval. Ersteres bedeutet, dass das System beispielsweise die Erstellung neuer Threads einschränkt, wenn die Anzahl der Threads zu groß ist. Letzteres bedeutet, dass der durch den zweiten Parameter dargestellte Thread-Attributwert unzulässig ist. Nachdem der Thread erfolgreich erstellt wurde, führt der neu erstellte Thread die durch Parameter drei und Parameter vier bestimmte Funktion aus, und der ursprüngliche Thread führt weiterhin die nächste Codezeile aus.

Drei pthread_join pthread_exit
 
Die Funktion pthread_join wird verwendet, um auf das Ende eines Threads zu warten. Der Funktionsprototyp lautet:
 extern int pthread_join __p ((pthread_t __th, void **__thread_return));
 Der erste Parameter ist die Thread-ID, auf die gewartet werden soll, und der zweite Parameter ist ein benutzerdefinierter Zeiger, der verwendet werden kann zu speichern Der Rückgabewert des erwarteten Threads. Diese Funktion ist eine Thread-blockierende Funktion. Die aufrufende Funktion wartet, bis der wartende Thread endet. Wenn die Funktion zurückkehrt, werden die Ressourcen des wartenden Threads wiederhergestellt. Es gibt zwei Möglichkeiten, einen Thread zu beenden: Wenn die Funktion endet, endet auch der Thread, der sie aufgerufen hat. Die andere Möglichkeit ist die Funktion pthread_exit. Sein Funktionsprototyp ist:
extern void pthread_exit __p ((void *__retval)) __attribute__ ((__noreturn__));
Der einzige Parameter ist der Rückkehrcode der Funktion, solange der zweite Parameter thread_return in pthread_join nicht null ist Der Wert wird an thread_return übergeben. Als letztes ist zu beachten, dass nicht mehrere Threads auf einen Thread warten können. Andernfalls kehrt der erste Thread, der das Signal empfängt, erfolgreich zurück und die verbleibenden Threads, die pthread_join aufrufen, geben den Fehlercode esrch zurück.
 In diesem Abschnitt haben wir den einfachsten Thread geschrieben und die drei am häufigsten verwendeten Funktionen beherrscht: pthread_create, pthread_join und pthread_exit. Schauen wir uns als Nächstes einige allgemeine Eigenschaften von Threads an und wie man sie festlegt.

Mutex-Sperre im Zusammenhang

Mutex-Sperre wird verwendet, um sicherzustellen, dass innerhalb eines bestimmten Zeitraums nur ein Thread einen Code ausführt.

一 pthread_mutex_init

Die Funktion pthread_mutex_init wird verwendet, um eine Mutex-Sperre zu generieren. Der Nullparameter gibt an, dass die Standardeigenschaften verwendet werden. Wenn Sie einen Mutex für ein bestimmtes Attribut deklarieren müssen, müssen Sie die Funktion pthread_mutexattr_init aufrufen. Die Funktion pthread_mutexattr_setpshared und die Funktion pthread_mutexattr_settype werden zum Festlegen der Mutex-Sperrattribute verwendet. Die vorherige Funktion legt das Attribut pshared fest, das zwei Werte hat: pthread_process_private und pthread_process_shared. Ersteres wird verwendet, um Threads in verschiedenen Prozessen zu synchronisieren, und letzteres wird verwendet, um verschiedene Threads in diesem Prozess zu synchronisieren. Im obigen Beispiel verwenden wir das Standardattribut pthread_process_private. Letzteres wird verwendet, um den Mutex-Sperrtyp festzulegen. Die optionalen Typen sind pthread_mutex_normal, pthread_mutex_errorcheck, pthread_mutex_recursive und pthread_mutex_default. Sie definieren jeweils unterschiedliche Auflistungs- und Entsperrmechanismen. Unter normalen Umständen wird das letzte Standardattribut ausgewählt.

Zwei pthread_mutex_lock pthread_mutex_unlock pthread_delay_np

Die pthread_mutex_lock-Anweisung beginnt mit der Sperre mit einer Mutex-Sperre. Der nachfolgende Code wird gesperrt, bis pthread_mutex_unlock aufgerufen wird, dh er kann nur von einem Thread gleichzeitig aufgerufen und ausgeführt werden. Wenn ein Thread pthread_mutex_lock ausführt und die Sperre zu diesem Zeitpunkt von einem anderen Thread verwendet wird, wird der Thread blockiert, dh das Programm wartet, bis ein anderer Thread die Mutex-Sperre aufhebt.

Hinweis:

1 Es ist zu beachten, dass die beiden oben genannten Ruhezustände nicht nur zu Demonstrationszwecken dienen, sondern auch dazu dienen, dem Thread eine gewisse Zeit lang den Ruhezustand zu ermöglichen, sodass der Thread die Mutex-Sperre aufheben und darauf warten kann, dass ein anderer Thread diese Sperre verwendet. Dieses Problem wird in Referenz 1 unten erläutert. Allerdings scheint es unter Linux keine pthread_delay_np-Funktion zu geben (ich habe es versucht und es wurde mir angezeigt, dass kein Verweis auf die definierte Funktion vorhanden ist), daher habe ich stattdessen Sleep verwendet. In Referenz 2 wird jedoch eine andere Methode angegeben, die dies zu tun scheint durch pthread_cond_timedwait ersetzt werden, was eine Möglichkeit bietet, dies zu erreichen.

2 Bitte beachten Sie die Kommentare 1-5 darin. Das ist das Problem, das ich mehrere Stunden lang herausgefunden habe.
Wenn Kommentar1, Kommentar4 und Kommentar5 nicht vorhanden sind, führt dies zu einem Segfault während pthread_join. Darüber hinaus sind die oben genannten Kommentare2 und Kommentar3 die Hauptursache. Denken Sie also daran, den gesamten Code zu schreiben. Da der obige Thread möglicherweise nicht erfolgreich erstellt werden kann, ist es unmöglich, auf das Ende dieses Threads zu warten, und bei Verwendung von pthread_join tritt ein Segmentierungsfehler auf (auf einen unbekannten Speicherbereich wird zugegriffen). Wenn Sie Memset verwenden, müssen Sie außerdem die Header-Datei string.h einbinden

Das obige ist der detaillierte Inhalt vonBeispielcode-Analyse für Linux-Multithread-Programmierung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen