生活随笔
收集整理的這篇文章主要介紹了
Linux多线程编程实例解析
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
Linux系統(tǒng)下的多線程遵循POSIX線程接口,稱為 pthread。編寫Linux下的多線程程序,需要使用頭文件pthread.h,連接時(shí)需要使用庫libpthread.a。順便說一下,Linux 下pthread的實(shí)現(xiàn)是通過系統(tǒng)調(diào)用clone()來實(shí)現(xiàn)的。clone()是 Linux所特有的系統(tǒng)調(diào)用,它的使用方式類似fork,關(guān)于clone()的詳細(xì)情況,有興趣的讀者可以去查看有關(guān)文檔說明。下面我們展示一個(gè)最簡單的 多線程程序 pthread_create.c。
一個(gè)重要的線程創(chuàng)建函數(shù)原型:
#include <pthread.h>
int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict attr, void *(*start_rtn)(void),void *restrict arg);
返回值:若是成功建立線程返回0,否則返回錯(cuò)誤的編號
形式參數(shù):
??????????????? pthread_t *restrict tidp 要創(chuàng)建的線程的線程id指針
??????????????? const pthread_attr_t *restrict attr 創(chuàng)建線程時(shí)的線程屬性
??????????????? void* (start_rtn)(void) 返回值是void類型的指針函數(shù)
??????????????? void *restrict arg?? start_rtn的行參
?????????????? ?
例程1:????????????????????????????? ?
??? 功能:創(chuàng)建一個(gè)簡單的線程
??? 程序名稱:pthread_create.c???
代碼如下:
[cpp]?view plaincopy
#include?<stdio.h>?? #include?<pthread.h>?? ?? void?*mythread1(void)?? {?? ????int?i;?? ????for(i?=?0;?i?<?10;?i++)?? ????{?? ????????printf("This?is?the?1st?pthread,created?by?xiaoqiang!\n");?? ????????sleep(1);?? ????}?? }?? ?? void?*mythread2(void)?? {?? ????int?i;?? ????for(i?=?0;?i?<?10;?i++)?? ????{?? ????????printf("This?is?the?2st?pthread,created?by?xiaoqiang!\n");?? ????????sleep(1);?? ????}?? }?? ?? int?main(int?argc,?const?char?*argv[])?? {?? ????int?i?=?0;?? ????int?ret?=?0;?? ????pthread_t?id1,id2;?? ?? ????ret?=?pthread_create(&id1,?NULL,?(void?*)mythread1,NULL);?? ????if(ret)?? ????{?? ????????printf("Create?pthread?error!\n");?? ????????return?1;?? ????}?? ?? ????ret?=?pthread_create(&id2,?NULL,?(void?*)mythread2,NULL);?? ????if(ret)?? ????{?? ????????printf("Create?pthread?error!\n");?? ????????return?1;?? ????}?? ?????? ????pthread_join(id1,NULL);?? ????pthread_join(id2,NULL);?? ?? ????return?0;?? }??
執(zhí)行結(jié)果如下:
[cpp]?view plaincopy
fs@ubuntu:~/qiang/thread$?vi?thread1.c?? fs@ubuntu:~/qiang/thread$?gcc?-o?thread1?thread1.c?-lpthread?? fs@ubuntu:~/qiang/thread$?./thread1?? This?is?the?2st?pthread,created?by?xiaoqiang!?? This?is?the?1st?pthread,created?by?xiaoqiang!?? This?is?the?2st?pthread,created?by?xiaoqiang!?? This?is?the?1st?pthread,created?by?xiaoqiang!?? This?is?the?2st?pthread,created?by?xiaoqiang!?? This?is?the?1st?pthread,created?by?xiaoqiang!?? This?is?the?2st?pthread,created?by?xiaoqiang!?? This?is?the?1st?pthread,created?by?xiaoqiang!?? This?is?the?2st?pthread,created?by?xiaoqiang!?? This?is?the?1st?pthread,created?by?xiaoqiang!?? This?is?the?2st?pthread,created?by?xiaoqiang!?? This?is?the?1st?pthread,created?by?xiaoqiang!?? This?is?the?1st?pthread,created?by?xiaoqiang!?? This?is?the?2st?pthread,created?by?xiaoqiang!?? This?is?the?2st?pthread,created?by?xiaoqiang!?? This?is?the?1st?pthread,created?by?xiaoqiang!?? This?is?the?1st?pthread,created?by?xiaoqiang!?? This?is?the?2st?pthread,created?by?xiaoqiang!?? This?is?the?2st?pthread,created?by?xiaoqiang!?? This?is?the?1st?pthread,created?by?xiaoqiang!?? fs@ubuntu:~/qiang/thread$???
兩個(gè)線程交替執(zhí)行。
另外,因?yàn)閜thread的庫不是linux系統(tǒng)的庫,所以在進(jìn)行編譯的時(shí)候要加上-lpthread,否則編譯不過,會出現(xiàn)下面錯(cuò)誤
thread_test.c: 在函數(shù) ‘create’ 中:
thread_test.c:7: 警告: 在有返回值的函數(shù)中,程序流程到達(dá)函數(shù)尾
/tmp/ccOBJmuD.o: In function `main':thread_test.c:(.text+0x4f):對‘pthread_create’未定義的引用
collect2: ld 返回 1
此例子介紹了創(chuàng)建線程的方法
?
下面例子介紹向線程傳遞參數(shù)。
例程2:
功能:向新的線程傳遞整形值
程序名稱:pthread_int.c
代碼如下:
[cpp]?view plaincopy
#include?<stdio.h>?? #include?<pthread.h>?? ?? void?*create(void?*arg)?? {?? ????int?*num;?? ????num?=?(int?*)arg;?? ????printf("Create?parameter?is?%d\n",*num);?? ????return?(void?*)0;?? }?? ?? int?main(int?argc,?const?char?*argv[])?? {?? ????pthread_t?id1;?? ????int?error;?? ?? ????int?test?=?4;?? ????int?*attr?=?&test;?? ?? ????error?=?pthread_create(&id1,NULL,create,(void?*)attr);?? ?? ????if(error)?? ????{?? ????????printf("Pthread_create?is?not?created!\n");?? ????????return?-1;?? ????}?? ????sleep(1);?? ?? ????printf("Pthread_create?is?created..\n");?? ????return?0;?? }??
執(zhí)行結(jié)果如下:
[cpp]?view plaincopy
fs@ubuntu:~/qiang/thread$?vi?thread2.c?? fs@ubuntu:~/qiang/thread$?gcc?-o?thread2?thread2.c?-lpthread?? fs@ubuntu:~/qiang/thread$?./thread2?? Create?parameter?is?4?? Pthread_create?is?created..?? fs@ubuntu:~/qiang/thread$???
例程總結(jié):
??? 可以看出來,我們在main函數(shù)中傳遞的整行指針,傳遞到我們新建的線程函數(shù)中。
在上面的例子可以看出來我們向新的線程傳入了另一個(gè)線程的int數(shù)據(jù),線程之間還可以傳遞字符串或是更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。
例程3:
程序功能:向新建的線程傳遞字符串
程序名稱:pthread_string.c
代碼如下:
[cpp]?view plaincopy
#include?<stdio.h>?? #include?<pthread.h>?? ?? void?*create(char?*arg)?? {?? ????char?*str;?? ????str?=?arg;?? ????printf("The?parameter?passed?from?main?is?%s\n",str);?? ?? ????return?(void?*)0;?? }?? ?? int?main()?? {?? ????int?error;?? ????pthread_t?id1;?? ????char?*str1?=?"Hello?,xiaoqiang!";?? ????char?*attr?=?str1;?? ????error?=?pthread_create(&id1,?NULL,?create,?(void?*)attr);?? ?? ????if(error?!=?0)?? ????{?? ????????printf("This?pthread?is?not?created!\n");?? ????????return?-1;?? ????}?? ????sleep(1);?? ?? ????printf("pthread?is?created..\n");?? ????return?0;?? }??
執(zhí)行結(jié)果如下:
[cpp]?view plaincopy
fs@ubuntu:~/qiang/thread$?./thread3?? The?parameter?passed?from?main?is?Hello?,xiaoqiang!?? pthread?is?created..?? fs@ubuntu:~/qiang/thread$???
例程總結(jié):
可以看出來main函數(shù)中的字符串傳入了新建的線程中。
例程4:
程序功能:向新建的線程傳遞字符串
程序名稱:pthread_struct.c
代碼如下:
[cpp]?view plaincopy
#include?<stdio.h>?? #include?<pthread.h>?? #include?<stdlib.h>?? ?? struct?menber?? {?? ????int?a;?? ????char?*s;?? };?? ?? void?*create(void?*arg)?? {?? ????struct?menber?*temp;?? ????temp?=?(struct?menber?*)arg;?? ????printf("menber->a?=?%d\n",temp->a);?? ????printf("menber->s?=?%s\n",temp->s);?? ?? ????return?(void?*)0;?? }?? ?? int?main()?? {?? ????int?error;?? ????pthread_t?id1;?? ????struct?menber?*p;?? ????p?=?(struct?menber?*)malloc(sizeof(struct?menber));?? ????p->a?=?1;?? ????p->s?=?"xiaoqiang!";?? ?? ????error?=?pthread_create(&id1,NULL,create,(void?*)p);?? ?? ????if(error)?? ????{?? ????????printf("pthread?is?not?created!\n");?? ????????return?-1;?? ????}?? ????sleep(1);?? ????printf("pthread?is?created!\n");?? ?? ????free(p);?? ????p?=?NULL;?? ????return?0;?? }??
執(zhí)行結(jié)果如下:
[cpp]?view plaincopy
fs@ubuntu:~/qiang/thread$?vi?thread4.c?? fs@ubuntu:~/qiang/thread$?gcc?-o?thread4?thread4.c?-lpthread?? fs@ubuntu:~/qiang/thread$?./thread4?? menber->a?=?1?? menber->s?=?xiaoqiang!?? pthread?is?created!?? fs@ubuntu:~/qiang/thread$???
例程總結(jié):
??? 可以看出來main函數(shù)中的一個(gè)結(jié)構(gòu)體傳入了新建的線程中。
??? 線程包含了標(biāo)識進(jìn)程內(nèi)執(zhí)行環(huán)境必須的信息。他集成了進(jìn)程中的所有信息都是對線程進(jìn)行共享的,包括文本程序、程序的全局內(nèi)存和堆內(nèi)存、棧以及文件描述符
例程5:
程序目的:驗(yàn)證新建立的線程可以共享進(jìn)程中的數(shù)據(jù)
程序名稱:pthread_share.c
代碼如下:
[cpp]?view plaincopy
#include?<stdio.h>?? #include?<pthread.h>?? ?? static?int?a?=?5;?? ?? void?*create(void?*arg)?? {?? ????printf("New?pthread...\n");?? ????printf("a?=?%d\n",a);?? ?? ????return?(void?*)0;?? }?? ?? int?main(int?argc,?const?char?*argv[])?? {?? ????int?error;?? ????pthread_t?id1;?? ?? ????error?=?pthread_create(&id1,?NULL,?create,?NULL);?? ????if(error?!=?0)?? ????{?? ????????printf("new?thread?is?not?created!\n");?? ????????return?-1;?? ????}?? ????sleep(1);?? ????printf("New?thread?is?created...\n");?? ?? ????return?0;?? }??
結(jié)果如下:
[cpp]?view plaincopy
fs@ubuntu:~/qiang/thread$?vi?thread5.c?? fs@ubuntu:~/qiang/thread$?gcc?-o?thread5?thread5.c?-lpthread?? fs@ubuntu:~/qiang/thread$?./thread5?? New?pthread...?? a?=?5?? New?thread?is?created...?? fs@ubuntu:~/qiang/thread$???
例程總結(jié):
可以看出來,我們在主線程更改了我們的全局變量a的值的時(shí)候,我們新建立的線程則打印出來了改變的值,可以看出可以訪問線程所在進(jìn)程中的數(shù)據(jù)信息。
2、線程的終止
如果進(jìn)程中任何一個(gè)線程中調(diào)用exit,_Exit,或者是_exit,那么整個(gè)進(jìn)程就會終止,
與此類似,如果信號的默認(rèn)的動作是終止進(jìn)程,那么,把該信號發(fā)送到線程會終止進(jìn)程。
線程的正常退出的方式:
(1) 線程只是從啟動例程中返回,返回值是線程中的退出碼
(2) 線程可以被另一個(gè)進(jìn)程進(jìn)行終止
(3) 線程自己調(diào)用pthread_exit函數(shù)
兩個(gè)重要的函數(shù)原型:
[cpp]?view plaincopy
include?<pthread.h>?? void?pthread_exit(void?*rval_ptr);?? ?? ?? int?pthread_join(pthread_t?thread,void?**rval_ptr);?? ?????
pthread_join使一個(gè)線程等待另一個(gè)線程結(jié)束。 代碼中如果沒有pthread_join主線程會很快結(jié)束從而使整個(gè)進(jìn)程結(jié)束,從而使創(chuàng)建的線程沒有機(jī)會開始執(zhí)行就結(jié)束了。加入pthread_join后,主線程會一直等待直到等待的線程結(jié)束自己才結(jié)束,使創(chuàng)建的線程有機(jī)會執(zhí)行。
頭文件 : #include <pthread.h>
函數(shù)定義: int pthread_join(pthread_t thread, void **retval);
描述 :pthread_join()函數(shù),以阻塞的方式等待thread指定的線程結(jié)束。當(dāng)函數(shù)返回時(shí),被等待線程的資源被收回。如果線程已經(jīng)結(jié)束,那么該函數(shù)會立即返回。并且thread指定的線程必須是joinable的。
參數(shù) :thread: 線程
標(biāo)識符,即線程ID,標(biāo)識唯一線程。retval: 用戶定義的指針,用來存儲被等待線程的返回值。
返回值 : 0代表成功。 失敗,返回的則是錯(cuò)誤號。
?
例程6
程序目的:線程正常退出,接受線程退出的返回碼
程序名稱:pthread_exit.c
執(zhí)行代碼如下:
[cpp]?view plaincopy
#include?<stdio.h>?? #include?<pthread.h>?? #include?<unistd.h>?? ?? void?*create(void?*arg)?? {?? ????printf("new?thread?is?created?...?\n");?? ????return?(void?*)0;?? }?? ?? int?main(int?argc,char?*argv[])?? {?? ????pthread_t?tid;?? ????int?error;?? ????void?*temp;?? ?? ????error?=?pthread_create(&tid,?NULL,?create,?NULL);?? ?? ????if(?error?)?? ????{?? ????????printf("thread?is?not?created?...?\n");?? ????????return?-1;?? ????}?? ????error?=?pthread_join(tid,?&temp);?? ?? ????if(?error?)?? ????{?? ????????printf("thread?is?not?exit?...?\n");?? ????????return?-2;?? ????}?? ?? ????printf("thread?is?exit?code?%d?\n",?(int?)temp);?? ?????????????????????????????????????????? ????return?0;?? }??
執(zhí)行結(jié)果如下:
[cpp]?view plaincopy
fs@ubuntu:~/qiang/thread$?vi?thread6.c?? fs@ubuntu:~/qiang/thread$?gcc?-o?thread6?thread6.c?-lpthread?? fs@ubuntu:~/qiang/thread$?./thread6?? new?thread?is?created?...??? thread?is?exit?code?0??? fs@ubuntu:~/qiang/thread$???
例程總結(jié):
可以看出來,線程退出可以返回線程的int數(shù)值。
線程退出不僅僅可以返回線程的int數(shù)值,還可以返回一個(gè)復(fù)雜的數(shù)據(jù)結(jié)構(gòu)
例程7
程序目的:線程結(jié)束返回一個(gè)復(fù)雜的數(shù)據(jù)結(jié)構(gòu) 代碼如下:
[cpp]?view plaincopy
#include?<stdio.h>?? #include?<pthread.h>?? #include?<unistd.h>?? ?? struct?menber?? {?? ????int?a;?? ????char?*b;?? }temp={8,"xiaoqiang"};?? ?? void?*create(void?*arg)?? {?? ????printf("new?thread?...?\n");?? ????return?(void?*)&temp;?? }?? ?? int?main(int?argc,char?*argv[])?? {?? ????int?error;?? ????pthread_t?tid;?? ????struct?menber?*c;?? ?? ????error?=?pthread_create(&tid,?NULL,?create,?NULL);?? ?? ????if(?error?)?? ????{?? ????????printf("new?thread?is?not?created?...?\n");?? ????????return?-1;?? ????}?? ????printf("main?...?\n");?? ?? ????error?=?pthread_join(tid,(void?*)&c);?? ?? ????if(?error?)?? ????{?? ????????printf("new?thread?is?not?exit?...?\n");?? ????????return?-2;?? ????}?? ????printf("c->a?=?%d??\n",c->a);?? ????printf("c->b?=?%s??\n",c->b);?? ????sleep(1);?? ????return?0;?? }?? 執(zhí)行結(jié)果如下:
[cpp]?view plaincopy
fs@ubuntu:~/qiang/thread$?gcc?-o?thread7?thread7.c?-lpthread?? fs@ubuntu:~/qiang/thread$?./thread7?? main?...??? new?thread?...??? c->a?=?8???? c->b?=?xiaoqiang???? fs@ubuntu:~/qiang/thread$??? 例程總結(jié):
一定要記得返回的數(shù)據(jù)結(jié)構(gòu)要是在這個(gè)數(shù)據(jù)要返回的結(jié)構(gòu)沒有釋放的時(shí)候應(yīng)用,如果數(shù)據(jù)結(jié)構(gòu)已經(jīng)發(fā)生變化,那返回的就不會是我們所需要的,而是臟數(shù)據(jù)。
3、線程標(biāo)識
????? 函數(shù)原型: #include <pthread.h>
pthread_t pthread_self(void);
pid_t getpid(void);
??? getpid()用來取得目前進(jìn)程的進(jìn)程識別碼,函數(shù)說明
例程8
程序目的:實(shí)現(xiàn)在新建立的線程中打印該線程的id和進(jìn)程id 代碼如下:
[cpp]?view plaincopy
#include?<stdio.h>?? #include?<pthread.h>?? #include?<unistd.h>?/*getpid()*/?? ?? void?*create(void?*arg)?? {?? ????printf("New?thread?....?\n");?? ????printf("This?thread's?id?is?%u??\n",?(unsigned?int)pthread_self());?? ????printf("The?process?pid?is?%d??\n",getpid());?? ????return?(void?*)0;?? }?? ?? int?main(int?argc,char?*argv[])?? {?? ????pthread_t?tid;?? ????int?error;?? ?? ????printf("Main?thread?is?starting?...?\n");?? ?? ????error?=?pthread_create(&tid,?NULL,?create,?NULL);?? ?? ????if(error)?? ????{?? ????????printf("thread?is?not?created?...?\n");?? ????????return?-1;?? ????}?? ????printf("The?main?process's?pid?is?%d??\n",getpid());?? ????sleep(1);?? ????return?0;?? }?? <span?style="font-family:Arial;BACKGROUND-COLOR:?#ffffff"></span>?? 執(zhí)行結(jié)果如下:
[cpp]?view plaincopy
fs@ubuntu:~/qiang/thread$?gcc?-o?thread8?thread8.c?-lpthread?? fs@ubuntu:~/qiang/thread$?./thread8?? Main?thread?is?starting?...??? The?main?process's?pid?is?4955???? New?thread?....??? This?thread's?id?is?3075853120???? The?process?pid?is?4955???? fs@ubuntu:~/qiang/thread$?
總結(jié)
以上是生活随笔為你收集整理的Linux多线程编程实例解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。