Linux多線程編程實例解析

  Linux系統(tǒng)下的多線程遵循POSIX線程接口刺洒,稱為

pthread装获。編寫Linux下的多線程程序,需要使用頭文件pthread.h光羞,連接時需要使用庫libpthread.a绩鸣。順便說一下,Linux

下pthread的實現(xiàn)是通過系統(tǒng)調用clone()來實現(xiàn)的纱兑。clone()是

Linux所特有的系統(tǒng)調用呀闻,它的使用方式類似fork,關于clone()的詳細情況潜慎,有興趣的讀者可以去查看有關文檔說明捡多。下面我們展示一個最簡單的 多線程程序

pthread_create.c。

  一個重要的線程創(chuàng)建函數(shù)原型:

  #include

  int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict

attr, void *(*start_rtn)(void),void *restrict arg);

  返回值:若是成功建立線程返回0,否則返回錯誤的編號

  形式參數(shù):

  pthread_t *restrict tidp 要創(chuàng)建的線程的線程id指針

  const pthread_attr_t *restrict attr 創(chuàng)建線程時的線程屬性

  void* (start_rtn)(void) 返回值是void類型的指針函數(shù)

  void *restrict arg start_rtn的行參

  例程1:

  功能:創(chuàng)建一個簡單的線程

  程序名稱:pthread_create.c

  代碼如下:

  #include

  #include

  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í)行結果如下:

  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$

  兩個線程交替執(zhí)行铐炫。

  另外局服,因為pthread的庫不是linux系統(tǒng)的庫,所以在進行編譯的時候要加上-lpthread驳遵,否則編譯不過淫奔,會出現(xiàn)下面錯誤

  thread_test.c: 在函數(shù) ‘create’ 中:

  thread_test.c:7: 警告: 在有返回值的函數(shù)中,程序流程到達函數(shù)尾

  /tmp/ccOBJmuD.o: In function

`main':thread_test.c:(.text+0x4f):對‘pthread_create’未定義的引用

  collect2: ld 返回 1

  此例子介紹了創(chuàng)建線程的方法

  下面例子介紹向線程傳遞參數(shù)堤结。

  例程2:

  功能:向新的線程傳遞整形值

  程序名稱:pthread_int.c

  代碼如下:

  #include

  #include

  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í)行結果如下:

  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函數(shù)中傳遞的整行指針,傳遞到我們新建的線程函數(shù)中竞穷。

  在上面的例子可以看出來我們向新的線程傳入了另一個線程的int數(shù)據唐责,線程之間還可以傳遞字符串或是更復雜的數(shù)據結構。

  例程3:

  程序功能:向新建的線程傳遞字符串

  程序名稱:pthread_string.c

  代碼如下:

  #include

  #include

  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í)行結果如下:

  fs@ubuntu:~/qiang/thread$ ./thread3

  The parameter passed from main is Hello ,xiaoqiang!

  pthread is created..

  fs@ubuntu:~/qiang/thread$

  例程總結:

  可以看出來main函數(shù)中的字符串傳入了新建的線程中瘾带。

  例程4:

  程序功能:向新建的線程傳遞字符串

  程序名稱:pthread_struct.c

  代碼如下:

  #include

  #include

  #include

  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í)行結果如下:

  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函數(shù)中的一個結構體傳入了新建的線程中鼠哥。

  線程包含了標識進程內執(zhí)行環(huán)境必須的信息。他集成了進程中的所有信息都是對線程進行共享的看政,包括文本程序朴恳、程序的全局內存和堆內存、棧以及文件描述符

  例程5:

  程序目的:驗證新建立的線程可以共享進程中的數(shù)據

  程序名稱:pthread_share.c

  代碼如下:

  #include

  #include

  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;

  }

  結果如下:

  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的值的時候于颖,我們新建立的線程則打印出來了改變的值,可以看出可以訪問線程所在進程中的數(shù)據信息嚷兔。

  2森渐、線程的終止

  如果進程中任何一個線程中調用exit做入,_Exit,或者是_exit,那么整個進程就會終止同衣,

  與此類似竟块,如果信號的默認的動作是終止進程,那么耐齐,把該信號發(fā)送到線程會終止進程浪秘。

  線程的正常退出的方式:

  (1) 線程只是從啟動例程中返回,返回值是線程中的退出碼

  (2) 線程可以被另一個進程進行終止

  (3) 線程自己調用pthread_exit函數(shù)

  兩個重要的函數(shù)原型:

  include

  void pthread_exit(void *rval_ptr);

  /*rval_ptr 線程退出返回的指針*/

  int pthread_join(pthread_t thread,void **rval_ptr);

  /*成功結束進程為0,否則為錯誤編碼*/

  pthread_join使一個線程等待另一個線程結束蚪缀。

  代碼中如果沒有pthread_join主線程會很快結束從而使整個進程結束,從而使創(chuàng)建的線程沒有機會開始執(zhí)行就結束了恕出。加入pthread_join后询枚,主線程會一直等待直到等待的線程結束自己才結束,使創(chuàng)建的線程有機會執(zhí)行浙巫。

  頭文件 : #include

  函數(shù)定義: int pthread_join(pthread_t thread, void **retval);

  描述

:pthread_join()函數(shù)金蜀,以阻塞的方式等待thread指定的線程結束。當函數(shù)返回時的畴,被等待線程的資源被收回渊抄。如果線程已經結束,那么該函數(shù)會立即返回丧裁。并且thread指定的線程必須是joinable的护桦。

  參數(shù) :thread: 線程標識符,即線程ID煎娇,標識唯一線程二庵。retval: 用戶定義的指針,用來存儲被等待線程的返回值缓呛。

  返回值 : 0代表成功催享。 失敗,返回的則是錯誤號哟绊。

  例程6

  程序目的:線程正常退出因妙,接受線程退出的返回碼

  程序名稱:pthread_exit.c

  執(zhí)行代碼如下:

  #include

  #include

  #include

  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í)行結果如下:

  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數(shù)值票髓。

  線程退出不僅僅可以返回線程的int數(shù)值攀涵,還可以返回一個復雜的數(shù)據結構

  例程7

  程序目的:線程結束返回一個復雜的數(shù)據結構

  代碼如下:

  #include

  #include

  #include

  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í)行結果如下:

  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$

  例程總結:

  一定要記得返回的數(shù)據結構要是在這個數(shù)據要返回的結構沒有釋放的時候應用,如果數(shù)據結構已經發(fā)生變化洽沟,那返回的就不會是我們所需要的汁果,而是臟數(shù)據。

  3玲躯、線程標識

  函數(shù)原型:

  #include

  pthread_t pthread_self(void);

  pid_t getpid(void);

  getpid()用來取得目前進程的進程識別碼,函數(shù)說明

  例程8

  程序目的:實現(xiàn)在新建立的線程中打印該線程的id和進程id

  代碼如下:

  #include

  #include

  #include /*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;

  }

  執(zhí)行結果如下:

  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多線程編程

  http://www.makeru.com.cn/course/details/1937?s=45051

  循環(huán)鏈表及線性表的應用

  http://www.makeru.com.cn/course/details/1902?s=45051

  linux基礎

  http://www.makeru.com.cn/course/details/2058?s=45051

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末据德,一起剝皮案震驚了整個濱河市鳄乏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌棘利,老刑警劉巖橱野,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異善玫,居然都是意外死亡水援,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門茅郎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蜗元,“玉大人,你說我怎么就攤上這事系冗∞瓤郏” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵掌敬,是天一觀的道長惯豆。 經常有香客問我,道長奔害,這世上最難降的妖魔是什么楷兽? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮华临,結果婚禮上芯杀,老公的妹妹穿的比我還像新娘。我一直安慰自己雅潭,他們只是感情好瘪匿,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著寻馏,像睡著了一般棋弥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上诚欠,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天顽染,我揣著相機與錄音,去河邊找鬼轰绵。 笑死粉寞,一個胖子當著我的面吹牛,可吹牛的內容都是我干的左腔。 我是一名探鬼主播唧垦,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼液样!你這毒婦竟也來了振亮?” 一聲冷哼從身側響起巧还,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎坊秸,沒想到半個月后麸祷,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡褒搔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年阶牍,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片星瘾。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡走孽,死狀恐怖,靈堂內的尸體忽然破棺而出琳状,到底是詐尸還是另有隱情磕瓷,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布算撮,位于F島的核電站生宛,受9級特大地震影響县昂,放射性物質發(fā)生泄漏肮柜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一倒彰、第九天 我趴在偏房一處隱蔽的房頂上張望审洞。 院中可真熱鬧,春花似錦待讳、人聲如沸芒澜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽痴晦。三九已至,卻和暖如春琳彩,著一層夾襖步出監(jiān)牢的瞬間誊酌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工露乏, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留碧浊,地道東北人。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓瘟仿,卻偏偏與公主長得像箱锐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子劳较,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354