GNU/Linux >> Znalost Linux >  >> Linux

Jak ukončit vlákno v programu C ( příklad pthread_exit )

V části II (Vytvoření a identifikace vlákna) série Linux Thread jsme diskutovali o ID vláken, jak porovnat dvě ID vláken a jak vytvořit vlákno.

V tomto článku se zaměříme hlavně na to, jak je vlákno ukončeno.

Linux Threads Series:část 1, část 2, část 3 (tento článek).

Příkladový program C vlákna

Vezmeme-li stejný příklad, jaký je popsán v části II této série:

#include<stdio.h>
#include<string.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>

pthread_t tid[2];

void* doSomeThing(void *arg)
{
    unsigned long i = 0;
    pthread_t id = pthread_self();

    if(pthread_equal(id,tid[0]))
    {
        printf("\n First thread processing\n");
    }
    else
    {
        printf("\n Second thread processing\n");
    }

    for(i=0; i<(0xFFFFFFFF);i++);

    return NULL;
}

int main(void)
{
    int i = 0;
    int err;

    while(i < 2)
    {
        err = pthread_create(&(tid[i]), NULL, &doSomeThing, NULL);
        if (err != 0)
            printf("\ncan't create thread :[%s]", strerror(err));
        else
            printf("\n Thread created successfully\n");

        i++;
    }

    sleep(5);
    return 0;
}

Všimli jste si použití funkce „sleep()“? Dostali jste otázku, proč se používá funkce sleep()? Pokud ano, pak jste na správném místě, abyste dostali odpověď, a pokud ne, bude to také dobré čtení dopředu.

Pokud z výše uvedeného kódu odstraním funkci sleep() a poté se ji pokusím zkompilovat a spustit, zobrazí se mi následující výstup:

$ ./threads
Thread created successfully
First thread processing
Thread created successfully

Ale pokud jej spustím s povolenou funkcí sleep(), pak výstup vidím jako  :

$ ./threads
Thread created successfully
First thread processing
Thread created successfully
Second thread processing

Vidíme tedy, že chybí protokol ‚Zpracování druhého vlákna‘ v případě, že odstraníme funkci sleep().

Proč se to děje? Stalo se to proto, že těsně předtím, než se má naplánovat druhé vlákno, dokončilo rodičovské vlákno (ze kterého byla dvě vlákna vytvořena) své spuštění. To znamená, že výchozí vlákno, ve kterém byla spuštěna funkce main(), bylo dokončeno, a proto byl proces ukončen jako main() vráceno.

Ukončení vlákna

Jak již bylo uvedeno výše, každý program začíná alespoň jedním vláknem, což je vlákno, ve kterém se provádí funkce main(). Maximální životnost každého vlákna spuštěného v programu je tedy životnost hlavního vlákna. Pokud tedy chceme, aby hlavní vlákno čekalo, dokud nebudou dokončena všechna ostatní vlákna, pak existuje funkce pthread_join().

#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);

Výše uvedená funkce zajišťuje, že její nadřazené vlákno se neukončí, dokud není hotovo. Tato funkce je volána z nadřazeného vlákna a první argument je ID vlákna, na které se má čekat, a druhý argument je návratová hodnota vlákna, na které chceme, aby nadřazené vlákno čekalo. Pokud nás návratová hodnota nezajímá, můžeme tento ukazatel nastavit na hodnotu NULL.

Pokud klasifikujeme na širší úrovni, pak vidíme, že vlákno může skončit třemi způsoby:

  1. Pokud se vlákno vrátí ze své úvodní rutiny.
  2. Pokud je zrušeno jiným vláknem. Zde použitá funkce je pthread_cancel().
  3. Pokud ze sebe sama zavolá funkci pthread_exit().

Zaměření by zde bylo na pthread_exit(). Jeho prototyp je následující:

#include <pthread.h>
void pthread_exit(void *rval_ptr);

Vidíme tedy, že tato funkce přijímá pouze jeden argument, což je návrat z vlákna, které tuto funkci volá. K této vrácené hodnotě přistupuje nadřazené vlákno, které čeká na ukončení tohoto vlákna. Návratová hodnota vlákna ukončeného funkcí pthread_exit() je dostupná ve druhém argumentu pthread_join, který byl právě vysvětlen výše.

Příklad ukončení vlákna C

Vezměme si příklad, kde použijeme výše diskutované funkce:

#include<stdio.h>
#include<string.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>

pthread_t tid[2];
int ret1,ret2;

void* doSomeThing(void *arg)
{
    unsigned long i = 0;
    pthread_t id = pthread_self();

    for(i=0; i<(0xFFFFFFFF);i++);

    if(pthread_equal(id,tid[0]))
    {
        printf("\n First thread processing done\n");
        ret1  = 100;
        pthread_exit(&ret1);
    }
    else
    {
        printf("\n Second thread processing done\n");
        ret2  = 200;
        pthread_exit(&ret2);
    }

    return NULL;
}

int main(void)
{
    int i = 0;  
    int err;
    int *ptr[2];

    while(i < 2)
    {
        err = pthread_create(&(tid[i]), NULL, &doSomeThing, NULL);
        if (err != 0)
            printf("\ncan't create thread :[%s]", strerror(err));
        else
            printf("\n Thread created successfully\n");

        i++;
    }

    pthread_join(tid[0], (void**)&(ptr[0]));
    pthread_join(tid[1], (void**)&(ptr[1]));

    printf("\n return value from first thread is [%d]\n", *ptr[0]);
    printf("\n return value from second thread is [%d]\n", *ptr[1]);

    return 0;
}

Ve výše uvedeném kódu:

  • Vytvořili jsme dvě vlákna pomocí pthread_create()
  • Funkce start pro obě vlákna je stejná, tj. doSomeThing()
  • Vlákna ukončí funkci start pomocí funkce pthread_exit() s návratovou hodnotou.
  • V hlavní funkci po vytvoření vláken jsou volány funkce pthread_join(), aby počkaly na dokončení dvou vláken.
  • Jakmile jsou obě vlákna dokončena, k jejich návratové hodnotě přistupuje druhý argument ve volání pthread_join().

Výstup výše uvedeného kódu vyjde jako  :

$ ./threads
Thread created successfully
Thread created successfully
First thread processing done
Second thread processing done
return value from first thread is [100]
return value from second thread is [200]

Vidíme tedy, že obě vlákna se kompletně provedou a jejich návratová hodnota je zpřístupněna ve funkci main.


Linux
  1. Příklad Python Hello World:Jak napsat a spustit program Python na OS Unix

  2. Příklad Ruby Hello World:Jak napsat a spustit program Ruby na OS Unix

  3. Příklad Perl Hello World:Jak napsat a spustit program Perl na OS Unix

  1. Příklad Cobol Hello World:Jak psát, kompilovat a spouštět program Cobol na OS Linux

  2. Jak pojmenovat vlákno v Linuxu?

  3. Jak získat ID vlákna pthread v programu linux c?

  1. Jak přesměrovat výstup programu do souboru ZIP?

  2. Příklad Pascal Hello World:Jak psát, kompilovat a spouštět program Pascal na OS Unix

  3. Smalltalk Hello World Příklad:Jak napsat a spustit program Smalltalk na OS Linux