生活随笔
收集整理的這篇文章主要介紹了
Linux多线程编程实例解析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Linux系統下的多線程遵循POSIX線程接口,稱為 pthread。編寫Linux下的多線程程序,需要使用頭文件pthread.h,連接時需要使用庫libpthread.a。順便說一下,Linux 下pthread的實現是通過系統調用clone()來實現的。clone()是 Linux所特有的系統調用,它的使用方式類似fork,關于clone()的詳細情況,有興趣的讀者可以去查看有關文檔說明。下面我們展示一個最簡單的 多線程程序 pthread_create.c。
一個重要的線程創建函數原型:
#include <pthread.h>
int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict attr, void *(*start_rtn)(void),void *restrict arg);
返回值:若是成功建立線程返回0,否則返回錯誤的編號
形式參數:
??????????????? pthread_t *restrict tidp 要創建的線程的線程id指針
??????????????? const pthread_attr_t *restrict attr 創建線程時的線程屬性
??????????????? void* (start_rtn)(void) 返回值是void類型的指針函數
??????????????? void *restrict arg?? start_rtn的行參
?????????????? ?
例程1:????????????????????????????? ?
??? 功能:創建一個簡單的線程
??? 程序名稱: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;?? }??
執行結果如下:
[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$???
兩個線程交替執行。
另外,因為pthread的庫不是linux系統的庫,所以在進行編譯的時候要加上-lpthread,否則編譯不過,會出現下面錯誤
thread_test.c: 在函數 ‘create’ 中:
thread_test.c:7: 警告: 在有返回值的函數中,程序流程到達函數尾
/tmp/ccOBJmuD.o: In function `main':thread_test.c:(.text+0x4f):對‘pthread_create’未定義的引用
collect2: ld 返回 1
此例子介紹了創建線程的方法
?
下面例子介紹向線程傳遞參數。
例程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;?? }??
執行結果如下:
[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$???
例程總結:
??? 可以看出來,我們在main函數中傳遞的整行指針,傳遞到我們新建的線程函數中。
在上面的例子可以看出來我們向新的線程傳入了另一個線程的int數據,線程之間還可以傳遞字符串或是更復雜的數據結構。
例程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;?? }??
執行結果如下:
[cpp]?view plaincopy
fs@ubuntu:~/qiang/thread$?./thread3?? The?parameter?passed?from?main?is?Hello?,xiaoqiang!?? pthread?is?created..?? fs@ubuntu:~/qiang/thread$???
例程總結:
可以看出來main函數中的字符串傳入了新建的線程中。
例程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;?? }??
執行結果如下:
[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$???
例程總結:
??? 可以看出來main函數中的一個結構體傳入了新建的線程中。
??? 線程包含了標識進程內執行環境必須的信息。他集成了進程中的所有信息都是對線程進行共享的,包括文本程序、程序的全局內存和堆內存、棧以及文件描述符
例程5:
程序目的:驗證新建立的線程可以共享進程中的數據
程序名稱: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;?? }??
結果如下:
[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$???
例程總結:
可以看出來,我們在主線程更改了我們的全局變量a的值的時候,我們新建立的線程則打印出來了改變的值,可以看出可以訪問線程所在進程中的數據信息。
2、線程的終止
如果進程中任何一個線程中調用exit,_Exit,或者是_exit,那么整個進程就會終止,
與此類似,如果信號的默認的動作是終止進程,那么,把該信號發送到線程會終止進程。
線程的正常退出的方式:
(1) 線程只是從啟動例程中返回,返回值是線程中的退出碼
(2) 線程可以被另一個進程進行終止
(3) 線程自己調用pthread_exit函數
兩個重要的函數原型:
[cpp]?view plaincopy
include?<pthread.h>?? void?pthread_exit(void?*rval_ptr);?? ?? ?? int?pthread_join(pthread_t?thread,void?**rval_ptr);?? ?????
pthread_join使一個線程等待另一個線程結束。 代碼中如果沒有pthread_join主線程會很快結束從而使整個進程結束,從而使創建的線程沒有機會開始執行就結束了。加入pthread_join后,主線程會一直等待直到等待的線程結束自己才結束,使創建的線程有機會執行。
頭文件 : #include <pthread.h>
函數定義: int pthread_join(pthread_t thread, void **retval);
描述 :pthread_join()函數,以阻塞的方式等待thread指定的線程結束。當函數返回時,被等待線程的資源被收回。如果線程已經結束,那么該函數會立即返回。并且thread指定的線程必須是joinable的。
參數 :thread: 線程
標識符,即線程ID,標識唯一線程。retval: 用戶定義的指針,用來存儲被等待線程的返回值。
返回值 : 0代表成功。 失敗,返回的則是錯誤號。
?
例程6
程序目的:線程正常退出,接受線程退出的返回碼
程序名稱:pthread_exit.c
執行代碼如下:
[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;?? }??
執行結果如下:
[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$???
例程總結:
可以看出來,線程退出可以返回線程的int數值。
線程退出不僅僅可以返回線程的int數值,還可以返回一個復雜的數據結構
例程7
程序目的:線程結束返回一個復雜的數據結構 代碼如下:
[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;?? }?? 執行結果如下:
[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$??? 例程總結:
一定要記得返回的數據結構要是在這個數據要返回的結構沒有釋放的時候應用,如果數據結構已經發生變化,那返回的就不會是我們所需要的,而是臟數據。
3、線程標識
????? 函數原型: #include <pthread.h>
pthread_t pthread_self(void);
pid_t getpid(void);
??? getpid()用來取得目前進程的進程識別碼,函數說明
例程8
程序目的:實現在新建立的線程中打印該線程的id和進程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>?? 執行結果如下:
[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$?
總結
以上是生活随笔為你收集整理的Linux多线程编程实例解析的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。