Linux 多線程編程(一)2019-08-05

\color{blue}{多線程}

  1. 線程是程序中完成一個(gè)獨(dú)立任務(wù)的完整執(zhí)行序列,即一個(gè)可以調(diào)度的實(shí)體;進(jìn)程是資源分配和調(diào)度的一個(gè)獨(dú)立單位,線程是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分配的基本單位.
  2. 一個(gè)進(jìn)程至少擁有一個(gè)線程,在同一個(gè)進(jìn)程中的多個(gè)線程的內(nèi)存資源是共享的.由于共享地址空間,所以多線程之間沒有通信的必要,但必須要做好數(shù)據(jù)的同步和互斥.
  3. 并發(fā)是指在一個(gè)時(shí)間段內(nèi),多個(gè)任務(wù)交替進(jìn)行,雖然看起來像是同時(shí)執(zhí)行,但其實(shí)是交替的.

線程控制函數(shù)

1.\color{blue}{創(chuàng)建線程}

#include <pthread.h>
int pthread_create(pthread_t* thread,const pthread_attr_t* attr,void*(*start_routine)(void*),void* arg);
//成功時(shí)返回值為0,失敗則返回錯(cuò)誤碼

attr參數(shù)可以用于設(shè)置新線程的屬性,給它傳NULL,表示使用默認(rèn)線程屬性.start_routine和arg參數(shù)分別指定新線程將運(yùn)行的函數(shù)及其參數(shù).
\color{blue}{實(shí)例}

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<pthread.h>

void* myfunc(void* arg)
{
   //打印子線程的ID
   printf("child thread ID= %ld\n",pthread_self());
   return 0;
}
int main(int argc,const char* argv[])
{
  //創(chuàng)建一個(gè)子線程
  //線程ID變量
  pthread_t pthid;
  //返回錯(cuò)誤號(hào)
  int ret=pthread_create(&pthid,NULL,myfunc,NULL);
  if (ret!=0)
  {
    printf("error number:%d\n",ret);
    //打印錯(cuò)誤信息
    printf("%s\n",sterror(ret));
  }
    
  printf("parent thread ID= %ld\n",pthread_self());
  for(int i=0;i<5;i++)
  {
     printf("I=%d\n",i);
  }
  sleep(2);
  return 0;
}

運(yùn)行結(jié)果:

parent thread ID= 140594076149504
I=0
I=1
I=2
child thread ID= 140594068010752
I=3
I=4

2.\color{blue}{線程退出}

 #include <pthread.h>
 void pthread_exit(void *retval);
    // 線程終止

pthread_exit可以通過retval參數(shù)向線程的回收者傳遞其退出的信息.

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

pthread_join()函數(shù),以阻塞的方式等待thread指定的線程結(jié)束.當(dāng)函數(shù)返回時(shí),被等待線程的資源被收回.thread參數(shù)是目標(biāo)線程的標(biāo)識(shí)符,retval參數(shù)則是目標(biāo)線程返回的退出信息,該函數(shù)會(huì)一直阻塞,直到被回收的線程結(jié)束為止,函數(shù)成功時(shí)返回值為0,失敗則返回錯(cuò)誤碼.
\color{blue}{實(shí)例}

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<pthread.h>
int num = 100; //堆內(nèi)存
void *myfunc(void *arg) {
    //打印子線程的ID
    printf("child thread ID= %ld\n", pthread_self());
    for (int i = 0; i < 5; i++) {
        printf("child I=%d\n", i);
        if (i == 2) {
            //退出攜帶信息
            pthread_exit(&num);
        }
    }
}
int main(int argc, const char *argv[]) {
    //創(chuàng)建一個(gè)子線程
    //線程ID變量
    pthread_t pthid;
    //返回錯(cuò)誤號(hào)
     int ret = pthread_create(&pthid, NULL, myfunc, NULL);
    if (ret != 0) {
        printf("error number:%d\n", ret);
        //打印錯(cuò)誤信息
        printf("%s\n", strerror(ret));
    }
    printf("parent thread ID= %ld\n", pthread_self());
    //阻塞等待子線程的退出,并且回收pcb
    void *ptr = NULL;
    pthread_join(pthid, &ptr);
    printf("number=%d\n", *(int *) ptr);
    for (int i = 0; i < 5; i++) {
        printf("parent I=%d\n", i);
    }
return 0;
}

運(yùn)行結(jié)果:

parent thread ID= 140099126167296
child thread ID= 140099118028544
child I=0
child I=1
child I=2
number=100
parent I=0
parent I=1
parent I=2
parent I=3
parent I=4

3.\color{blue}{線程取消}
有時(shí)我們想要異常終止一個(gè)線程,即取消線程.

#include <pthread.h>
int pthread_cancel(pthread_t thread);
//成功時(shí)返回值為0,失敗則返回錯(cuò)誤碼

不過,接收到取消請(qǐng)求的目標(biāo)線程可以決定是否允許被取消以及如何取消,這分別由以下兩個(gè)函數(shù)來控制:

#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldstate);

4.\color{blue}{線程屬性設(shè)置}
常用的屬性:我們一般想要線程在結(jié)束時(shí),自動(dòng)釋放其線程資源,自動(dòng)回收pcb,則就需要給線程設(shè)置屬性為detach,即線程分離.設(shè)置完之后就不需要調(diào)用pthread_join再進(jìn)行線程回收了.
常用的函數(shù)與參數(shù):
函數(shù)原型: int pthread_detach(pthread_t pthid);
設(shè)置屬性類型:pthread_attr_t attr;
對(duì)線程屬性變量初始化:int pthread_attr_init(pthread_attr_t* attr);
設(shè)置屬性時(shí)通用做法:
代碼上,可以這樣表示:
pthread_t pthid;
pthread_attr_t attr; //線程屬性
pthread_attr_init(&attr); //初始化線程屬性
pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED); //設(shè)置線程屬性
pthread_create( &pthid, &attr,myfunc, NULL); //建立線程
\color{blue}{實(shí)例}

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<pthread.h>

void *myfunc(void *arg) {
    //打印子線程的ID
    printf("child thread ID= %ld\n", pthread_self());
    for (int i = 0; i < 5; i++) {
        printf("child I=%d\n", i);
        if (i == 2) {
            pthread_exit(NULL);
        }
    }
}
int main(int argc, const char *argv[]) {
    //創(chuàng)建一個(gè)子線程
    //線程ID變量
    pthread_t pthid;
    //返回錯(cuò)誤號(hào)
    //初始化線程屬性
    pthread_attr_t attr;
    pthread_attr_init(&attr);

/*  int pthread_attr_init(pthread_attr_t* attr);*/
    //設(shè)置分離
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    //創(chuàng)建線程時(shí)就設(shè)置線程分離
    int ret = pthread_create(&pthid, &attr, myfunc, NULL);
    if (ret != 0) {
        printf("error number:%d\n", ret);
        //打印錯(cuò)誤信息
        printf("%s\n", strerror(ret));
    }
    printf("parent thread ID= %ld\n", pthread_self());
    //退出主線程,子線程不受影響
    //由于主線程退出,下面的不執(zhí)行
    for (int i = 0; i < 5; i++) {
        printf("parent I=%d\n", i);
    }
    sleep(2);
    //釋放資源
    pthread_attr_destroy(&attr);
    return 0;
}

運(yùn)行結(jié)果:

parent thread ID= 139976127342336
parent I=0
child thread ID= 139976119203584
child I=0
child I=1
child I=2
parent I=1
parent I=2
parent I=3
parent I=4

5.\color{blue}{循環(huán)創(chuàng)建線程}

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<pthread.h>

void *myfunc(void *arg) {
    int num = arg;
    //打印子線程的ID
    printf("%dth child thread ID= %ld\n", num, pthread_self());
    return 0;
}
int main(int argc, const char *argv[]) {
    //創(chuàng)建一個(gè)子線程
    //線程ID變量
    pthread_t pthid[5];
    for (int i = 0; i < 5; i++) {  //第四個(gè)參數(shù)傳遞的是按值傳遞,可以對(duì)子線程標(biāo)號(hào),而傳地址則不行,公用一個(gè)地址,注意此時(shí)不在為null了
/*     pthread_create(&pthid[i],NULL,myfunc,(void*)&i);*/
        pthread_create(&pthid[i], NULL, myfunc, (void *) i);
    }
    printf("parent thread ID= %ld\n", pthread_self());
    for (int i = 0; i < 5; i++) {
        printf("I=%d\n", i);
    }
    sleep(2);
    return 0;
}

運(yùn)行結(jié)果:

1th child thread ID= 140415359592192
2th child thread ID= 140415351199488
0th child thread ID= 140415367984896
3th child thread ID= 140415342806784
4th child thread ID= 140415334414080
parent thread ID= 140415376123648
I=0
I=1
I=2
I=3
I=4
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)自:Youtherhttps://www.cnblogs.com/youtherhome/archive/201...
    njukay閱讀 1,719評(píng)論 0 52
  • 線程基礎(chǔ) 線程是進(jìn)程的一個(gè)執(zhí)行單元,執(zhí)行一段程序片段,線程共享全局變量;線程的查看可以使用命令或者文件來進(jìn)行查看;...
    秋風(fēng)弄影閱讀 802評(píng)論 0 0
  • 概述 線程和進(jìn)程本質(zhì)上來說都屬于一個(gè)內(nèi)核調(diào)度單元,也就是說都可以作為一條單獨(dú)的執(zhí)行路徑。但是多進(jìn)程程序通常有一些限...
    loopppp閱讀 533評(píng)論 0 0
  • 簡介 線程創(chuàng)建 線程屬性設(shè)置 線程參數(shù)傳遞 線程優(yōu)先級(jí) 線程的數(shù)據(jù)處理 線程的分離狀態(tài) 互斥鎖 信號(hào)量 一 線程創(chuàng)...
    第八區(qū)閱讀 8,709評(píng)論 1 6
  • Linux-創(chuàng)建進(jìn)程與線程用到的函數(shù)解析 【1】exit: exit函數(shù)可以退出程序并將控制權(quán)返回給操作系統(tǒng),而用...
    Yojiaku閱讀 3,677評(píng)論 0 2

友情鏈接更多精彩內(nèi)容