日韩欧美自拍在线观看-欧美精品在线看片一区二区-高清性视频一区二区播放-欧美日韩女优制服另类-国产精品久久久久久av蜜臀-成人在线黄色av网站-肥臀熟妇一区二区三区-亚洲视频在线播放老色-在线成人激情自拍视频

基于Linux系統(tǒng)下的多線程簡單編程

出處:互聯(lián)網(wǎng)    發(fā)布于:2011-09-04 17:10:11

 引言
  早在60年代線程( thread, 在臺灣稱作執(zhí)行緒 是"進(jìn)程"中某個單一順序的控制流。)技術(shù)就被提出,但真正應(yīng)用多線程到操作系統(tǒng)中去卻是在80年代中期。這就不得不說個人了,他就是solaris,這方面的佼佼者。傳統(tǒng)的Unix也支持線程的概念,但是在一個進(jìn)程(process,是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ);是一個正在執(zhí)行的程序;計算機(jī)中正在運(yùn)行的程序?qū)嵗豢梢苑峙浣o處理器并由處理器執(zhí)行的一個實體;由單一順序的執(zhí)行顯示,一個當(dāng)前狀態(tài)和一組相關(guān)的系統(tǒng)資源所描述的活動單元。)中只允許有一個線程,這樣多線程就意味著多進(jìn)程。這樣就大大影響了效率。現(xiàn)在,多線程技術(shù)已經(jīng)被許多操作系統(tǒng)所支持,包括Windows/NT,當(dāng)然,也包括Linux。就比如以前你能看網(wǎng)頁就不能玩游戲,玩了游戲就不能看網(wǎng)頁,而現(xiàn)在你能邊玩游戲邊看網(wǎng)頁上的東西了。所以說我們現(xiàn)在可以邊聽音樂邊寫文,或者看網(wǎng)上的書都有著多線進(jìn)程的功勞。接下來讓我們首先了解下進(jìn)程,線程以及多線程。

   簡介進(jìn)程,線程以及多線程

  在Linux 操作系統(tǒng)中,一個進(jìn)程(Process)相當(dāng)于一個任務(wù)(Task),進(jìn)程具有一段可執(zhí)行的程序、專用的系統(tǒng)堆棧空間、私有的"進(jìn)程控制塊"(即task_struct 數(shù)據(jù)結(jié)構(gòu))和獨立的存儲空間。

  內(nèi)核空間是通過進(jìn)程模擬線程的, 在用戶空間用pthread 創(chuàng)建線程。與進(jìn)程相似,但是沒有自己的存儲空間。 

    接著我們說說多線程。通常單獨一個程序運(yùn)行時, 缺省的包含一個主線程,主線程以函數(shù)地址的形式(如main 函數(shù))提供程序的啟動點,這就是單進(jìn)程單線程的情況。若在main 函數(shù)中創(chuàng)建多個線程,則該程序運(yùn)行時,操作系統(tǒng)為每個線程分配不同的CPU 時間片,并根據(jù)線程優(yōu)先級進(jìn)行調(diào)度。由于每個時間片時間很短, 看上去好象各個線程是并發(fā)執(zhí)行的, 實際上同一時刻只有一個線程在運(yùn)行,這就是單進(jìn)程多線程的情況。若用fork 函數(shù)創(chuàng)建多個進(jìn)程,而每個進(jìn)程只采用默認(rèn)的一個主線程,則程序運(yùn)行時,由內(nèi)核調(diào)度操作系統(tǒng),將cpu 分配給各個進(jìn)程使用,這就是多進(jìn)程的情況。

  在前面我們知道了進(jìn)程,線程以及多線程。但是我們還不知道為什么在有了進(jìn)程的概念后,還要再引入線程呢?有必要性嗎?使用多線程好處在哪里?什么的系統(tǒng)應(yīng)該選用多線程?現(xiàn)在我們就來回答這些問題。

  我們使用多線程的個理由是和進(jìn)程相比,它是一種非常"節(jié)儉"的多任務(wù)操作方式。我們知道,在Linux系統(tǒng)下,啟動一個新的進(jìn)程必須分配給它獨立的地址空間,建立眾多的數(shù)據(jù)表來維護(hù)它的代碼段、堆棧段和數(shù)據(jù)段,這是一種"昂貴"的多任務(wù)工作方式。而運(yùn)行于一個進(jìn)程中的多個線程,它們彼此之間使用相同的地址空間,共享大部分?jǐn)?shù)據(jù),啟動一個線程所花費(fèi)的空間遠(yuǎn)遠(yuǎn)小于啟動一個進(jìn)程所花費(fèi)的空間,而且,線程間彼此切換所需的時間也遠(yuǎn)遠(yuǎn)小于進(jìn)程間切換所需要的時間。據(jù)統(tǒng)計,總的說來兩者相差20倍左右,當(dāng)然,在具體的系統(tǒng)上,這個數(shù)據(jù)可能會有較大的區(qū)別。但是相差很是明顯的。

  我們使用多線程的第二個理由是線程間方便的通信機(jī)制。每個不同進(jìn)程,它們都具有獨立的數(shù)據(jù)空間,要進(jìn)行數(shù)據(jù)的傳遞只能通過通信的方式進(jìn)行,這種方式不僅費(fèi)時,而且很不方便。線程則不一樣,由于同一進(jìn)程下的線程之間共享數(shù)據(jù)空間,所以一個線程的數(shù)據(jù)可以直接為其它線程所用,這不僅快捷,而且方便。當(dāng)然,數(shù)據(jù)的共享也帶來其他一些問題,有的變量不能同時被兩個線程所修改,有的子程序中聲明為static的數(shù)據(jù)更有可能給多線程程序帶來災(zāi)難性的打擊,這些正是編寫多線程程序時需要注意的地方。

  知道了以上兩大優(yōu)點,不和進(jìn)程比較,多線程程序作為一種多任務(wù)、并發(fā)的工作方式,當(dāng)然還有著以下的優(yōu)點:

  1  使多CPU系統(tǒng)更加有效。操作系統(tǒng)會保證當(dāng)線程數(shù)不大于CPU數(shù)目時,不同的線程運(yùn)行于不同的CPU上。  

    2  提高應(yīng)用程序響應(yīng)。這對圖形界面的程序尤其有意義,當(dāng)一個操作耗時很長時,整個系統(tǒng)都會等待這個操作,此時程序不會響應(yīng)鍵盤、鼠標(biāo)、菜單的操作,而使用多線程技術(shù),將耗時長的操作(time consuming)置于一個新的線程,可以避免這種尷尬的情況。就如我們常遇到的因為某件程序機(jī)子卡了,什么事情都不能做了。現(xiàn)在當(dāng)然我們可以把那個導(dǎo)致卡機(jī)的程序關(guān)掉一切問題就解決了。但是在沒有多線程程序的那會就不能這么做了,只能干等那個程序完全運(yùn)行起來。  

    3  改善程序結(jié)構(gòu)。一個既長又復(fù)雜的進(jìn)程可以考慮分為多個線程,成為幾個獨立或半獨立的運(yùn)行部分,這樣的程序會利于理解和修改。

  總的來說可以把一個正在運(yùn)行的軟件看做一個進(jìn)程,就像一個大的管道,這個管道不運(yùn)送什么東西,但里面有很多個小的管道,每個小管負(fù)責(zé)的東西不同~~而這些小管道就可以看做是一個個線程~如果運(yùn)行的是一個單線程的程序的話,而這個線程需要連續(xù)運(yùn)行幾個功能時,如果正在運(yùn)行的那個功能因碰到一個等待或者睡眠的指令的話,他就會停在那里不做任何事,此是這個CPU就空閑在那里,同時還會等待知道程序重新繼續(xù)運(yùn)行~~如果使用多線程技術(shù),那么可以把這幾個功能同時(并不是意義上的同時)運(yùn)行,當(dāng)其中一個功能遇到睡眠指令的時候,其他沒有睡眠的繼續(xù)運(yùn)行,這個可以花更短的時間,讓CPU更充分的被利用來完成需要的事情,線程通常共享一個代碼區(qū),但有各自獨立的數(shù)據(jù)存儲區(qū)。

  當(dāng)然每件事都有兩面性,在這里也是一樣的。在單cpu 的機(jī)器上,采用多進(jìn)程單線程(每個進(jìn)程只創(chuàng)建一個線程) 和單進(jìn)程多線程(一個進(jìn)程創(chuàng)建多個線程)模型來設(shè)計程序,后者(多線程)的上下文切換開銷就比前者要小的多。雖然多線程提供的優(yōu)點是單個線程的進(jìn)程所欠缺的,但是它們也不乏一些缺點:

  * 由于線程間共享存儲器和進(jìn)程狀態(tài), 一個線程的動作可能會對同一個進(jìn)程中的其他線程產(chǎn)生影響。例如當(dāng)兩個線程同一時刻訪問同一個變量時, 他們之間就會產(chǎn)生相互干擾。

  * 當(dāng)多個線程試圖并發(fā)調(diào)用同一個庫函數(shù)時, 返回結(jié)果是不可預(yù)知的。如果多個線程調(diào)用某個庫函數(shù), 線程之間必須互相加以協(xié)調(diào), 確保某個時刻只有一個線程調(diào)用該庫函數(shù)。

  * 缺乏健壯性, 在單線程的操作系統(tǒng)中, 如果某個存儲器出錯, 操作系統(tǒng)會終止引發(fā)故障的進(jìn)程, 但是在多線程操作系統(tǒng)中, 如果一個線程出錯, 操作系統(tǒng)將終止整個進(jìn)程, 從而其他的無關(guān)線程也被終止了。這與線程的正常終止是不同的。線程正常終止時可以通過調(diào)用exit 函數(shù)終止它所在的整個進(jìn)程, 也可以終止自己而不影響進(jìn)程內(nèi)的其他線程。可以在主線程返回時終止該線程, 也可以調(diào)用pthreaad_exit 終止該線程。  

    接下來讓我們就先來嘗試編寫一個簡單的多線程程序。

  簡單的多線程編程
  Linux系統(tǒng)下的多線程遵循POSIX(可移植操作系統(tǒng)接口)線程接口,稱為pthread。編寫基于Linux下的多線程程序,需要使用頭文件pthread.h,連接時需要使用庫libpthread.a。順便說一下,Linux下pthread的實現(xiàn)是通過系統(tǒng)調(diào)用clone()來實現(xiàn)的。clone()是Linux所特有的系統(tǒng)調(diào)用,它的使用方式類似fork,關(guān)于clone()的詳細(xì)情況,有興趣的話可以查看相關(guān)書籍。下面我們展示兩個個簡單的多線程程序example1.c和pthread_create.c 。

    首先來看下多線程程序example1.c
   

/* example.c*/
#include <stdio.h>
#include <pthread.h>
void thread(void)
{
 int i;
 for(i=0;i<3;i )
  printf("This is a pthread.n");
}
int main(void)
{
 pthread_t id;
 int i,ret;
 ret=pthread_create(&id,NULL,(void *) thread,NULL);
 if(ret!=0){
  printf ("Create pthread error!n");
  exit (1);
 }
 for(i=0;i<3;i )
  printf("This is the main process.n");
 pthread_join(id,NULL);
 return (0);
}


  我們編譯此程序:

gcc example1.c -lpthread -o example1


  運(yùn)行example1,我們得到如下結(jié)果:

This is the main process.
This is a pthread.
This is the main process.
This is the main process.
This is a pthread.
This is a pthread.


  再次運(yùn)行,我們可能得到如下結(jié)果:

This is a pthread.
This is the main process.
This is a pthread.
This is the main process.
This is a pthread.
This is the main process.

  前后兩次結(jié)果不一樣,這是兩個線程爭奪CPU資源的結(jié)果。上面的示例中,我們使用到了兩個函數(shù),pthread_create和pthread_join,并聲明了一個pthread_t型的變量。

  pthread_t在頭文件/usr/include/bits/pthreadtypes.h中定義:

  typedef unsigned long int pthread_t;

  它是一個線程的標(biāo)識符。函數(shù)pthread_create用來創(chuàng)建一個線程,它的原型為:

extern int pthread_create __P ((pthread_t *__thread, __const pthread_attr_t *__attr,void *(*__start_routine) (void *), void *__arg));


  個參數(shù)為指向線程標(biāo)識符的指針,第二個參數(shù)用來設(shè)置線程屬性,第三個參數(shù)是線程運(yùn)行函數(shù)的起始地址,一個參數(shù)是運(yùn)行函數(shù)的參數(shù)。這里,我們的函數(shù)thread不需要參數(shù),所以一個參數(shù)設(shè)為空指針。第二個參數(shù)我們也設(shè)為空指針,這樣將生成默認(rèn)屬性的線程。對線程屬性的設(shè)定和修改我們將在下一節(jié)闡述。當(dāng)創(chuàng)建線程成功時,函數(shù)返回0,若不為0則說明創(chuàng)建線程失敗,常見的錯誤返回代碼為EAGAIN和EINVAL。前者表示系統(tǒng)限制創(chuàng)建新的線程,例如線程數(shù)目過多了;后者表示第二個參數(shù)代表的線程屬性值非法。在創(chuàng)建線程成功后,新創(chuàng)建的線程則運(yùn)行參數(shù)三和參數(shù)四確定的函數(shù),原來的線程則繼續(xù)運(yùn)行下一行代碼。

  函數(shù)pthread_join用來等待一個線程的結(jié)束。函數(shù)原型為:

  extern int pthread_join __P ((pthread_t __th, void **__thread_return));

  個參數(shù)為被等待的線程標(biāo)識符,第二個參數(shù)為一個用戶定義的指針,它可以用來存儲被等待線程的返回值。這個函數(shù)是一個線程阻塞的函數(shù),調(diào)用它的函數(shù)將一直等待到被等待的線程結(jié)束為止,當(dāng)函數(shù)返回時,被等待線程的資源被收回。一個線程的結(jié)束有兩種途徑,一種是象我們上面的例子一樣,函數(shù)結(jié)束了,調(diào)用它的線程也就結(jié)束了;另一種方式是通過函數(shù)pthread_exit來實現(xiàn)。它的函數(shù)原型為:

  extern void pthread_exit __P ((void *__retval)) __attribute__ ((__noreturn__));

  的參數(shù)是函數(shù)的返回代碼,只要pthread_join中的第二個參數(shù)thread_return不是NULL,這個值將被傳遞給thread_return。要說明的是,一個線程不能被多個線程等待,否則個接收到信號的線程成功返回,其余調(diào)用pthread_join的線程則返回錯誤代碼ESRCH。

  我們來看看pthread_create.c是怎么樣的。

  ********************************************************************************************

  **    Name:pthread_create.c

  **    Used to study the multithread programming in Linux OS

  **    Author:zeickey

  **    Date:2006/9/16

  **    Copyright (c) 2006,All Rights Reserved!

  *********************************************************************************************/

  #include

  #include

  void *myThread1(void)

  {

  int i;

  for (i=0; i

  #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 ,char *argv[])

  {

  pthread_t tidp;

  int error;

  int test=4;

  int *attr=&test;

  error=pthread_create(&tidp,NULL,create,(void *)attr);

  if(error)

  {

  printf("pthread_create is created is not created … \n");

  return -1;

  }

  sleep(1);

  printf("pthread_create is created …\n");

  return 0;

  }

  編譯方法:

  gcc -lpthread pthread_int.c -Wall

  執(zhí)行結(jié)果:

  create parameter is 4

  pthread_create is created is  created …

  例程總結(jié):

  可以看出來,我們在main函數(shù)中傳遞的整行指針,傳遞到我們新建的線程函數(shù)中。

  在這一節(jié)里,我們學(xué)習(xí)了如何編寫簡單的線程,并掌握了常用的幾個函數(shù)pthread_create,pthread_join,pthread_exit和main。下面,我們來了解線程的一些常用屬性以及如何設(shè)置這些屬性。

  修改線程的屬性

  在上面的例子里,我們用pthread_create函數(shù)創(chuàng)建了一個線程,在這個線程中,我們使用了默認(rèn)參數(shù),即將該函數(shù)的第二個參數(shù)設(shè)為NULL。的確,對大多數(shù)程序來說,使用默認(rèn)屬性就夠了,但我們還是有必要來了解一下線程的有關(guān)屬性。

  屬性結(jié)構(gòu)為pthread_attr_t,它同樣在頭文件/usr/include/pthread.h中定義,喜歡追根問底的人可以自己去查看。屬性值不能直接設(shè)置,須使用相關(guān)函數(shù)進(jìn)行操作,初始化的函數(shù)為pthread_attr_init,這個函數(shù)必須在pthread_create函數(shù)之前調(diào)用。屬性對象主要包括是否綁定、是否分離、堆棧地址、堆棧大小、優(yōu)先級。默認(rèn)的屬性為非綁定、非分離、缺省1M的堆棧、與父進(jìn)程同樣級別的優(yōu)先級。

  通常我們在說到線程的綁定的時候,會牽涉到另外一個概念:輕進(jìn)程(LWP:Light Weight Process)。輕進(jìn)程可以理解為內(nèi)核線程,它位于用戶層和系統(tǒng)層之間。系統(tǒng)對線程資源的分配、對線程的控制是通過輕進(jìn)程來實現(xiàn)的,一個輕進(jìn)程可以控制一個或多個線程。默認(rèn)狀況下,啟動多少輕進(jìn)程、哪些輕進(jìn)程來控制哪些線程是由系統(tǒng)來控制的,這種狀況即稱為非綁定的。綁定狀況下,則顧名思義,即某個線程固定的"綁"在一個輕進(jìn)程之上。被綁定的線程具有較高的響應(yīng)速度,這是因為CPU時間片的調(diào)度是面向輕進(jìn)程的,綁定的線程可以保證在需要的時候它總有一個輕進(jìn)程可用。通過設(shè)置被綁定的輕進(jìn)程的優(yōu)先級和調(diào)度級可以使得綁定的線程滿足諸如實時反應(yīng)之類的要求。

  設(shè)置線程綁定狀態(tài)的函數(shù)為pthread_attr_setscope,它有兩個參數(shù),個是指向?qū)傩越Y(jié)構(gòu)的指針,第二個是綁定類型,它有兩個取值:PTHREAD_SCOPE_SYSTEM(綁定的)和PTHREAD_SCOPE_PROCESS(非綁定的)。下面的代碼即創(chuàng)建了一個綁定的線程。

#include <pthread.h>
pthread_attr_t attr;
pthread_t tid;
/*初始化屬性值,均設(shè)為默認(rèn)值*/
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
pthread_create(&tid, &attr, (void *) my_function, NULL);


  線程的分離狀態(tài)決定一個線程以什么樣的方式來終止自己。在上面的例子中,我們采用了線程的默認(rèn)屬性,即為非分離狀態(tài),這種情況下,原有的線程等待創(chuàng)建的線程結(jié)束。只有當(dāng)pthread_join()函數(shù)返回時,創(chuàng)建的線程才算終止,才能釋放自己占用的系統(tǒng)資源。而分離線程不是這樣子的,它沒有被其他的線程所等待,自己運(yùn)行結(jié)束了,線程也就終止了,馬上釋放系統(tǒng)資源。程序員應(yīng)該根據(jù)自己的需要,選擇適當(dāng)?shù)姆蛛x狀態(tài)。設(shè)置線程分離狀態(tài)的函數(shù)為pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)。第二個參數(shù)可選為PTHREAD_CREATE_DETACHED(分離線程)和 PTHREAD _CREATE_JOINABLE(非分離線程)。這里要注意的一點是,如果設(shè)置一個線程為分離線程,而這個線程運(yùn)行又非常快,它很可能在pthread_create函數(shù)返回之前就終止了,它終止以后就可能將線程號和系統(tǒng)資源移交給其他的線程使用,這樣調(diào)用pthread_create的線程就得到了錯誤的線程號。要避免這種情況可以采取一定的同步措施,簡單的方法之一是可以在被創(chuàng)建的線程里調(diào)用pthread_cond_timewait函數(shù),讓這個線程等待一會兒,留出足夠的時間讓函數(shù)pthread_create返回。設(shè)置一段等待時間,是在多線程編程里常用的方法。但是注意不要使用諸如wait()之類的函數(shù),它們是使整個進(jìn)程睡眠,并不能解決線程同步的問題。

  另外一個可能常用的屬性是線程的優(yōu)先級,它存放在結(jié)構(gòu)sched_param中。用函數(shù)pthread_attr_getschedparam和函數(shù)pthread_attr_setschedparam進(jìn)行存放,一般說來,我們總是先取優(yōu)先級,對取得的值修改后再存放回去。下面即是一段簡單的例子。

#include <pthread.h>
#include <sched.h>
pthread_attr_t attr;
pthread_t tid;
sched_param param;
int newprio=20;
pthread_attr_init(&attr);
pthread_attr_getschedparam(&attr, &param);
param.sched_priority=newprio;
pthread_attr_setschedparam(&attr, &param);
pthread_create(&tid, &attr, (void *)myfunction, myarg);

   線程的數(shù)據(jù)處理

  與進(jìn)程相比,線程的優(yōu)點之一是具有數(shù)據(jù)的共享性,各個進(jìn)程共享父進(jìn)程處沿襲的數(shù)據(jù)段,可以方便的獲得、修改數(shù)據(jù)。但這也給多線程編程帶來了許多問題。我們必須當(dāng)心有多個不同的進(jìn)程訪問相同的變量。許多函數(shù)是不可重入的,即同時不能運(yùn)行一個函數(shù)的多個拷貝(除非使用不同的數(shù)據(jù)段)。在函數(shù)中聲明的靜態(tài)變量常常帶來問題,函數(shù)的返回值也會有問題。因為如果返回的是函數(shù)內(nèi)部靜態(tài)聲明的空間的地址,則在一個線程調(diào)用該函數(shù)得到地址后使用該地址指向的數(shù)據(jù)時,別的線程可能調(diào)用此函數(shù)并修改了這一段數(shù)據(jù)。在進(jìn)程中共享的變量必須用關(guān)鍵字volatile來定義,這是為了防止編譯器在優(yōu)化時(如gcc中使用-OX參數(shù))改變它們的使用方式。為了保護(hù)變量,我們必須使用信號量、互斥等方法來保證我們對變量的正確使用。

  多線程開發(fā)在 Linux 平臺上已經(jīng)有成熟的 Pthread 庫支持。其涉及的多線程開發(fā)的基本概念主要包含三點:線程,互斥鎖,條件。其中,線程操作又分線程的創(chuàng)建,退出,等待 3 種。互斥鎖則包括 4 種操作,分別是創(chuàng)建,銷毀,加鎖和解鎖。條件操作有 5 種操作:創(chuàng)建,銷毀,觸發(fā),廣播和等待。其他的一些線程擴(kuò)展概念,如信號燈等,都可以通過上面的三個基本元素的基本操作封裝出來。

  線程,互斥鎖,條件在 Linux 平臺上對應(yīng)的 API 可以用表 1 歸納。為了方便熟悉 Windows 線程編程的讀者熟悉 Linux 多線程開發(fā)的 API,我們在表中同時也列出 Windows SDK 庫中所對應(yīng)的 API 名稱。


  多線程開發(fā)在 Linux 平臺上已經(jīng)有成熟的 Pthread 庫支持。其涉及的多線程開發(fā)的基本概念主要包含三點:線程,互斥鎖,條件。其中,線程操作又分線程的創(chuàng)建,退出,等待 3 種。互斥鎖則包括 4 種操作,分別是創(chuàng)建,銷毀,加鎖和解鎖。條件操作有 5 種操作:創(chuàng)建,銷毀,觸發(fā),廣播和等待。其他的一些線程擴(kuò)展概念,如信號燈等,都可以通過上面的三個基本元素的基本操作封裝出來。下面,我們就逐步介紹處理線程數(shù)據(jù)時的有關(guān)知識。

  1  線程數(shù)據(jù)

  在單線程的程序里,有兩種基本的數(shù)據(jù):局部變量以及全局變量。但在多線程程序里,還有第三種數(shù)據(jù)類型:線程數(shù)據(jù)(TSD: Thread-Specific Data)。它和全局變量很象,在線程內(nèi)部,各個函數(shù)可以象使用全局變量一樣調(diào)用它,但它對線程外部的其它線程是不可見的。這種數(shù)據(jù)的必要性是顯而易見的。例如我們常見的變量errno,它返回標(biāo)準(zhǔn)的出錯信息。它顯然不能是一個局部變量,幾乎每個函數(shù)都應(yīng)該可以調(diào)用它;但它又不能是一個全局變量,否則在A線程里輸出的很可能是B線程的出錯信息。要實現(xiàn)諸如此類的變量,我們就必須使用線程數(shù)據(jù)。我們?yōu)槊總€線程數(shù)據(jù)創(chuàng)建一個鍵,它和這個鍵相關(guān)聯(lián),在各個線程里,都使用這個鍵來指代線程數(shù)據(jù),但在不同的線程里,這個鍵代表的數(shù)據(jù)是不同的,在同一個線程里,它代表同樣的數(shù)據(jù)內(nèi)容。

  和線程數(shù)據(jù)相關(guān)的函數(shù)主要有4個:創(chuàng)建一個鍵;為一個鍵指定線程數(shù)據(jù);從一個鍵讀取線程數(shù)據(jù);刪除鍵。

  創(chuàng)建鍵的函數(shù)原型為:

extern int pthread_key_create __P ((pthread_key_t *__key,void (*__destr_function) (void *)));

  
  個參數(shù)為指向一個鍵值的指針,第二個參數(shù)指明了一個destructor函數(shù),如果這個參數(shù)不為空,那么當(dāng)每個線程結(jié)束時,系統(tǒng)將調(diào)用這個函數(shù)來釋放綁定在這個鍵上的內(nèi)存塊。這個函數(shù)常和函數(shù)pthread_once ((pthread_once_t*once_control, void (*initroutine) (void)))一起使用,為了讓這個鍵只被創(chuàng)建。函數(shù)pthread_once聲明一個初始化函數(shù),次調(diào)用pthread_once時它執(zhí)行這個函數(shù),以后的調(diào)用將被它忽略。

  在下面的例子中,我們來學(xué)習(xí)創(chuàng)建一個鍵,并將它和某個數(shù)據(jù)相關(guān)聯(lián)。希望能給大家一個直觀的展現(xiàn)。我們要定義一個函數(shù)createWindow,這個函數(shù)定義一個圖形窗口(數(shù)據(jù)類型為Fl_Window *,這是圖形界面開發(fā)工具FLTK中的數(shù)據(jù)類型)。由于各個線程都會調(diào)用這個函數(shù),所以我們使用線程數(shù)據(jù)。

/* 聲明一個鍵*/
pthread_key_t myWinKey;
/* 函數(shù) createWindow */
void createWindow ( void ) {
 Fl_Window * win;
 static pthread_once_t once= PTHREAD_ONCE_INIT;
 /* 調(diào)用函數(shù)createMyKey,創(chuàng)建鍵*/
 pthread_once ( & once, createMyKey) ;
 /*win指向一個新建立的窗口*/
 win=new Fl_Window( 0, 0, 100, 100, "MyWindow");
 /* 對此窗口作一些可能的設(shè)置工作,如大小、位置、名稱等*/
 setWindow(win);
 /* 將窗口指針值綁定在鍵myWinKey上*/
 pthread_setpecific ( myWinKey, win);
}
/* 函數(shù) createMyKey,創(chuàng)建一個鍵,并指定了destructor */
void createMyKey ( void ) {
 pthread_keycreate(&myWinKey, freeWinKey);
}
/* 函數(shù) freeWinKey,釋放空間*/
void freeWinKey ( Fl_Window * win){
 delete win;
}


  這樣,在不同的線程中調(diào)用函數(shù)createMyWin,都可以得到在線程內(nèi)部均可見的窗口變量,這個變量通過函數(shù)pthread_getspecific得到。在上面的例子中,我們已經(jīng)使用了函數(shù)pthread_setspecific來將線程數(shù)據(jù)和一個鍵綁定在一起。這兩個函數(shù)的原型如下:

  extern int pthread_setspecific __P ((pthread_key_t __key,__const void *__pointer));
  extern void *pthread_getspecific __P ((pthread_key_t __key));

  這兩個函數(shù)的參數(shù)意義以及使用方法是顯而易見的。要注意的是用pthread_setspecific為一個鍵指定新的線程數(shù)據(jù)時,必須自己釋放原有的線程數(shù)據(jù)以回收空間。這個過程函數(shù)pthread_key_delete用來刪除一個鍵,這個鍵占用的內(nèi)存將被釋放,但同樣要注意的是,它只釋放鍵占用的內(nèi)存,并不釋放該鍵關(guān)聯(lián)的線程數(shù)據(jù)所占用的內(nèi)存資源,而且它也不會觸發(fā)函數(shù)pthread_key_create中定義的destructor函數(shù)。線程數(shù)據(jù)的釋放必須在釋放鍵之前完成。

  2  互斥鎖

  互斥鎖是多線程編程中基本的概念,在開發(fā)中被廣泛使用。互斥鎖用來保證一段時間內(nèi)只有一個線程在執(zhí)行一段代碼。必要性顯而易見:假設(shè)各個線程向同一個文件順序?qū)懭霐?shù)據(jù),得到的結(jié)果一定是災(zāi)難性的。還需要注意的是,與諸如 Windows 平臺的互斥變量不同,在默認(rèn)情況下,Linux 下的同一線程無法對同一互斥鎖進(jìn)行遞歸加速,否則將發(fā)生死鎖。

  我們先看下面一段代碼。這是一個讀/寫程序,它們公用一個緩沖區(qū),并且我們假定一個緩沖區(qū)只能保存一條信息。即緩沖區(qū)只有兩個狀態(tài):有信息或沒有信息。

void reader_function ( void );
void writer_function ( void );
char buffer;
int buffer_has_item=0;
pthread_mutex_t mutex;
struct timespec delay;
void main ( void ){
 pthread_t reader;
 /* 定義延遲時間*/
 delay.tv_sec = 2;
 delay.tv_nec = 0;
 /* 用默認(rèn)屬性初始化一個互斥鎖對象*/
 pthread_mutex_init (&mutex,NULL);
 pthread_create(&reader, pthread_attr_default, (void *)&reader_function), NULL);
 writer_function( );
}
void writer_function (void){
 while(1){
  /* 鎖定互斥鎖*/
  pthread_mutex_lock (&mutex);
  if (buffer_has_item==0){
   buffer=make_new_item( );
   buffer_has_item=1;
  }
  /* 打開互斥鎖*/
  pthread_mutex_unlock(&mutex);
  pthread_delay_np(&delay);
 }
}
void reader_function(void){
 while(1){
  pthread_mutex_lock(&mutex);
  if(buffer_has_item==1){
   consume_item(buffer);
   buffer_has_item=0;
  }
  pthread_mutex_unlock(&mutex);
  pthread_delay_np(&delay);
 }
}


  這里聲明了互斥鎖變量mutex,結(jié)構(gòu)pthread_mutex_t為不公開的數(shù)據(jù)類型,其中包含一個系統(tǒng)分配的屬性對象。函數(shù)pthread_mutex_init用來生成一個互斥鎖。NULL參數(shù)表明使用默認(rèn)屬性。如果需要聲明特定屬性的互斥鎖,須調(diào)用函數(shù)pthread_mutexattr_init。函數(shù)pthread_mutexattr_setpshared和函數(shù)pthread_mutexattr_settype用來設(shè)置互斥鎖屬性。前一個函數(shù)設(shè)置屬性pshared,它有兩個取值,PTHREAD_PROCESS_PRIVATE和PTHREAD_PROCESS_SHARED。前者用來不同進(jìn)程中的線程同步,后者用于同步本進(jìn)程的不同線程。在上面的例子中,我們使用的是默認(rèn)屬性PTHREAD_PROCESS_ PRIVATE。后者用來設(shè)置互斥鎖類型,可選的類型有PTHREAD_MUTEX_NORMAL、PTHREAD_MUTEX_ERRORCHECK、PTHREAD_MUTEX_RECURSIVE和PTHREAD _MUTEX_DEFAULT。它們分別定義了不同的上所、解鎖機(jī)制,一般情況下,選用一個默認(rèn)屬性。

  pthread_mutex_lock聲明開始用互斥鎖上鎖,此后的代碼直至調(diào)用pthread_mutex_unlock為止,均被上鎖,即同一時間只能被一個線程調(diào)用執(zhí)行。當(dāng)一個線程執(zhí)行到pthread_mutex_lock處時,如果該鎖此時被另一個線程使用,那此線程被阻塞,即程序?qū)⒌却搅硪粋€線程釋放此互斥鎖。在上面的例子中,我們使用了pthread_delay_np函數(shù),讓線程睡眠一段時間,就是為了防止一個線程始終占據(jù)此函數(shù)。

  上面給出的例子非常簡單,就不再過多地介紹了,需要提出的是在使用互斥鎖的過程中很有可能會出現(xiàn)死鎖:兩個線程試圖同時占用兩個資源,并按不同的次序鎖定相應(yīng)的互斥鎖,例如兩個線程都需要鎖定互斥鎖1和互斥鎖2,a線程先鎖定互斥鎖1,b線程先鎖定互斥鎖2,這時就出現(xiàn)了死鎖。此時我們可以使用函數(shù)pthread_mutex_trylock,它是函數(shù)pthread_mutex_lock的非阻塞版本,當(dāng)它發(fā)現(xiàn)死鎖不可避免時,它會返回相應(yīng)的信息,程序員可以針對死鎖做出相應(yīng)的處理。另外不同的互斥鎖類型對死鎖的處理不一樣,但主要的還是要程序員自己在程序設(shè)計注意這一點。

  3  條件變量

  前一節(jié)中我們講述了如何使用互斥鎖來實現(xiàn)線程間數(shù)據(jù)的共享和通信,互斥鎖一個明顯的缺點是它只有兩種狀態(tài):鎖定和非鎖定。而條件變量通過允許線程阻塞和等待另一個線程發(fā)送信號的方法彌補(bǔ)了互斥鎖的不足,它常和互斥鎖一起使用。使用時,條件變量被用來阻塞一個線程,當(dāng)條件不滿足時,線程往往解開相應(yīng)的互斥鎖并等待條件發(fā)生變化。一旦其它的某個線程改變了條件變量,它將通知相應(yīng)的條件變量喚醒一個或多個正被此條件變量阻塞的線程。這些線程將重新鎖定互斥鎖并重新測試條件是否滿足。一般說來,條件變量被用來進(jìn)行線承間的同步。條件變量的置位和復(fù)位有兩種常用模型:種模型是當(dāng)條件變量置位(signaled)以后,如果當(dāng)前沒有線程在等待,其狀態(tài)會保持為置位(signaled),直到有等待的線程進(jìn)入被觸發(fā),其狀態(tài)才會變?yōu)閺?fù)位(unsignaled),這種模型的采用以 Windows 平臺上的 Auto-set Event 為代表。

  條件變量的結(jié)構(gòu)為pthread_cond_t,函數(shù)pthread_cond_init()被用來初始化一個條件變量。它的原型為:

  extern int pthread_cond_init __P ((pthread_cond_t *__cond,__const pthread_condattr_t *__cond_attr));

  其中cond是一個指向結(jié)構(gòu)pthread_cond_t的指針,cond_attr是一個指向結(jié)構(gòu)pthread_condattr_t的指針。結(jié)構(gòu)pthread_condattr_t是條件變量的屬性結(jié)構(gòu),和互斥鎖一樣我們可以用它來設(shè)置條件變量是進(jìn)程內(nèi)可用還是進(jìn)程間可用,默認(rèn)值是PTHREAD_ PROCESS_PRIVATE,即此條件變量被同一進(jìn)程內(nèi)的各個線程使用。注意初始化條件變量只有未被使用時才能重新初始化或被釋放。釋放一個條件變量的函數(shù)為pthread_cond_ destroy(pthread_cond_t cond)。

  函數(shù)pthread_cond_wait()使線程阻塞在一個條件變量上。它的函數(shù)原型為:

  extern int pthread_cond_wait __P ((pthread_cond_t *__cond,pthread_mutex_t *__mutex));

  線程解開mutex指向的鎖并被條件變量cond阻塞。線程可以被函數(shù)pthread_cond_signal和函數(shù)pthread_cond_broadcast喚醒,但是要注意的是,條件變量只是起阻塞和喚醒線程的作用,具體的判斷條件還需用戶給出,例如一個變量是否為0等等,這一點我們從后面的例子中可以看到。線程被喚醒后,它將重新檢查判斷條件是否滿足,如果還不滿足,一般說來線程應(yīng)該仍阻塞在這里,被等待被下喚醒。這個過程一般用while語句實現(xiàn)。

  另一個用來阻塞線程的函數(shù)是pthread_cond_timedwait(),它的原型為:

  extern int pthread_cond_timedwait __P ((pthread_cond_t *__cond,pthread_mutex_t *__mutex, __const struct timespec *__abstime));

  它比函數(shù)pthread_cond_wait()多了一個時間參數(shù),經(jīng)歷abstime段時間后,即使條件變量不滿足,阻塞也被解除。

  函數(shù)pthread_cond_signal()的原型為:

  extern int pthread_cond_signal __P ((pthread_cond_t *__cond));

  它用來釋放被阻塞在條件變量cond上的一個線程。多個線程阻塞在此條件變量上時,哪一個線程被喚醒是由線程的調(diào)度策略所決定的。要注意的是,必須用保護(hù)條件變量的互斥鎖來保護(hù)這個函數(shù),否則條件滿足信號又可能在測試條件和調(diào)用pthread_cond_wait函數(shù)之間被發(fā)出,從而造成無限制的等待。下面是使用函數(shù)pthread_cond_wait()和函數(shù)pthread_cond_signal()的一個簡單的例子。

pthread_mutex_t count_lock;
pthread_cond_t count_nonzero;
unsigned count;
decrement_count () {
 pthread_mutex_lock (&count_lock);
 while(count==0)
  pthread_cond_wait( &count_nonzero, &count_lock);
  count=count -1;
 pthread_mutex_unlock (&count_lock);
}
increment_count(){
 pthread_mutex_lock(&count_lock);
 if(count==0)
  pthread_cond_signal(&count_nonzero);
  count=count 1;
 pthread_mutex_unlock(&count_lock);
}

  count值為0時,decrement函數(shù)在pthread_cond_wait處被阻塞,并打開互斥鎖count_lock。此時,當(dāng)調(diào)用到函數(shù)increment_count時,pthread_cond_signal()函數(shù)改變條件變量,告知decrement_count()停止阻塞。讀者可以試著讓兩個線程分別運(yùn)行這兩個函數(shù),看看會出現(xiàn)什么樣的結(jié)果。

  函數(shù)pthread_cond_broadcast(pthread_cond_t *cond)用來喚醒所有被阻塞在條件變量cond上的線程。這些線程被喚醒后將再次競爭相應(yīng)的互斥鎖,所以必須小心使用這個函數(shù)。

  4  信號量

  信號量本質(zhì)上是一個非負(fù)的整數(shù)計數(shù)器,它被用來控制對公共資源的訪問。當(dāng)公共資源增加時,調(diào)用函數(shù)sem_post()增加信號量。只有當(dāng)信號量值大于0時,才能使用公共資源,使用后,函數(shù)sem_wait()減少信號量。函數(shù)sem_trywait()和函數(shù)pthread_ mutex_trylock()起同樣的作用,它是函數(shù)sem_wait()的非阻塞版本。下面我們逐個介紹和信號量有關(guān)的一些函數(shù),它們都在頭文件/usr/include/semaphore.h中定義。

  信號量的數(shù)據(jù)類型為結(jié)構(gòu)sem_t,它本質(zhì)上是一個長整型的數(shù)。函數(shù)sem_init()用來初始化一個信號量。它的原型為:

  extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));

  sem為指向信號量結(jié)構(gòu)的一個指針;pshared不為0時此信號量在進(jìn)程間共享,否則只能為當(dāng)前進(jìn)程的所有線程共享;value給出了信號量的初始值。

  函數(shù)sem_post( sem_t *sem )用來增加信號量的值。當(dāng)有線程阻塞在這個信號量上時,調(diào)用這個函數(shù)會使其中的一個線程不在阻塞,選擇機(jī)制同樣是由線程的調(diào)度策略決定的。

  函數(shù)sem_wait( sem_t *sem )被用來阻塞當(dāng)前線程直到信號量sem的值大于0,解除阻塞后將sem的值減一,表明公共資源經(jīng)使用后減少。函數(shù)sem_trywait ( sem_t *sem )是函數(shù)sem_wait()的非阻塞版本,它直接將信號量sem的值減一。

  函數(shù)sem_destroy(sem_t *sem)用來釋放信號量sem。

  接下來下面我們來看一個使用信號量的例子。在這個例子中一共有4個線程,其中兩個線程負(fù)責(zé)從文件讀取數(shù)據(jù)到公共的緩沖區(qū),另兩個線程從緩沖區(qū)讀取數(shù)據(jù)作不同的處理(加和乘運(yùn)算)。

/* File sem.c */
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#define MAXSTACK 100
int stack[MAXSTACK][2];
int size=0;
sem_t sem;
/* 從文件1.dat讀取數(shù)據(jù),每讀,信號量加一*/
void ReadData1(void){
 FILE *fp=fopen("1.dat","r");
 while(!feof(fp)){
  fscanf(fp,"%d %d",&stack[size][0],&stack[size][1]);
  sem_post(&sem);
   size;
 }
 fclose(fp);
}
/*從文件2.dat讀取數(shù)據(jù)*/
void ReadData2(void){
 FILE *fp=fopen("2.dat","r");
 while(!feof(fp)){
  fscanf(fp,"%d %d",&stack[size][0],&stack[size][1]);
  sem_post(&sem);
   size;
 }
 fclose(fp);
}
/*阻塞等待緩沖區(qū)有數(shù)據(jù),讀取數(shù)據(jù)后,釋放空間,繼續(xù)等待*/
void HandleData1(void){
 while(1){
  sem_wait(&sem);
  printf("Plus:%d %d=%dn",stack[size][0],stack[size][1],
  stack[size][0] stack[size][1]);
  --size;
 }
}
void HandleData2(void){
 while(1){
  sem_wait(&sem);
  printf("Multiply:%d*%d=%dn",stack[size][0],stack[size][1],
  stack[size][0]*stack[size][1]);
  --size;
 }
}
int main(void){
 pthread_t t1,t2,t3,t4;
 sem_init(&sem,0,0);
 pthread_create(&t1,NULL,(void *)HandleData1,NULL);
 pthread_create(&t2,NULL,(void *)HandleData2,NULL);
 pthread_create(&t3,NULL,(void *)ReadData1,NULL);
 pthread_create(&t4,NULL,(void *)ReadData2,NULL);
 /* 防止程序過早退出,讓它在此無限期等待*/
 pthread_join(t1,NULL);
}

  在Linux下,我們用命令gcc -lpthread sem.c -o sem生成可執(zhí)行文件sem。 我們事先編輯好數(shù)據(jù)文件1.dat和2.dat,假設(shè)它們的內(nèi)容分別為1 2 3 4 5 6 7 8 9 10和 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 ,我們運(yùn)行sem,得到如下的結(jié)果:

  Multiply:-1*-2=2

  Plus:-1 -2=-3

  Multiply:9*10=90

  Plus:-9 -10=-19

  Multiply:-7*-8=56

  Plus:-5 -6=-11

  Multiply:-3*-4=12

  Plus:9 10=19

  Plus:7 8=15

  Plus:5 6=11

  從中我們可以看出各個線程間的競爭關(guān)系。而數(shù)值并未按我們原先的順序顯示出來這是由于size這個數(shù)值被各個線程任意修改的緣故。這也往往是多線程編程要注意的問題。

   線程標(biāo)識

  函數(shù)原型:

  #include

  pthread_t pthread_self(void);

  pid_t getpid(void);

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

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

  程序名稱:pthread_id.c

  /********************************************************************************************

  **    Name:pthread_id.c

  **    Used to study the multithread programming in Linux OS.

  **    Showing how to get the thread's tid and the process's pid.

  **    Author:zeickey

  **    Date:2006/9/16

  **    Copyright (c) 2006,All Rights Reserved!

  *********************************************************************************************/

  #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;

  }

  編譯方法:

  gcc -Wall -lpthread pthread_id.c

  執(zhí)行結(jié)果:

  Main thread is starting …

  The main process's pid is 3307

  New thread …

  This thread's id is 3086347152

  The process pid is 3307

  線程的終止

  如果進(jìn)程中任何一個線程中調(diào)用exit,_Exit,或者是_exit,那么整個進(jìn)程就會終止,與此類似,如果信號的默認(rèn)的動作是終止進(jìn)程,那么,把該信號發(fā)送到線程會終止進(jìn)程。線程的正常退出的方式:

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

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

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

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

  #include

  void pthread_exit(void *rval_ptr);

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

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

  /*成功結(jié)束進(jìn)程為0,否則為錯誤編碼*/

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

  程序名稱:pthread_exit.c

  /********************************************************************************************

  **    Name:pthread_exit.c

  **    Used to study the multithread programming in Linux OS

  **    A example showing a thread to exit and with a return code.

  **    Author:zeickey

  **    Date:2006/9/16

  **    Copyright (c) 2006,All Rights Reserved!

  *********************************************************************************************/

  #include

  #include

  #include

  void *create(void *arg)

  {

  printf("new thread is created … \n");

  return (void *)8;

  }

  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;

  }

  編譯方法:

  gcc -Wall pthread_exit.c -lpthread

  執(zhí)行結(jié)果:

  new thread is created …

  thread is exit code 8

  例程總結(jié):

  可以看出來,線程退出可以返回線程的int數(shù)值。線程退出不僅僅可以返回線程的int數(shù)值,還可以返回一個復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。

  程序目的:線程結(jié)束返回一個復(fù)雜的數(shù)據(jù)結(jié)構(gòu)

  程序名稱:pthread_return_struct.c

  #include

  #include

  #include

  struct menber

  {

  int a;

  char *b;

  }temp={8,"zieckey"};

  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;

  }

  編譯方法:

  gcc -Wall pthread_return_struct.c -lpthread

  執(zhí)行結(jié)果:

  main …

  new thread …

  c->a = 8

  c->b = zieckey

  例程總結(jié):

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

    在 Linux 平臺下,當(dāng)處理線程結(jié)束時需要注意的一個問題就是如何讓一個線程善始善終,讓其所占資源得到正確釋放。在 Linux 平臺默認(rèn)情況下,雖然各個線程之間是相互獨立的,一個線程的終止不會去通知或影響其他的線程。但是已經(jīng)終止的線程的資源并不會隨著線程的終止而得到釋放,我們需要調(diào)用 pthread_join() 來獲得另一個線程的終止?fàn)顟B(tài)并且釋放該線程所占的資源

    多線程的未來

    信息的世界發(fā)展是非常迅速的。多線程技術(shù)也不例外在不斷發(fā)展著。 近日據(jù)相關(guān)消息透露,在HotChips會議上,AMD宣布下一代代號為Bulldozer“推土機(jī)”的處理器架構(gòu)將采用單核多線程技術(shù)(multi-threadingtechnology),類似于Intel的超線程技術(shù)。

  超線程(HT)是英特爾所研發(fā)的一種技術(shù),于2002年發(fā)布。超線程的英文是HT技術(shù),全名為Hyper-Threading,中文又名超線程。超線程技術(shù)原先只應(yīng)用于Xeon處理器中,當(dāng)時稱為Super-Threading。之后陸續(xù)應(yīng)用在Pentium 4中,將技術(shù)主流化。早期代號為Jackson。

  AMD沒有透露有關(guān)其多線程能力和更多的細(xì)節(jié),只說推土機(jī)處理器將在2011年推出,支持單核多線程技術(shù)。不過,AMD的做法和Intel的 HT是不同的,更類似于Sun的同步多線程技術(shù)(SimultaneousMulti-Threading),由1個物理擴(kuò)展到4個線程。“推土機(jī)擴(kuò)展出的單多線程技術(shù)和Intel的超線程采用的是不同方式。”AMD的代表PatConway也證實了這一點。 有趣的是,早些時候AMD還表示暫不考慮SMT或其他多線程技術(shù),并將它應(yīng)用在當(dāng)下的處理器中。然而,AMD也認(rèn)同步多線程是未來處理器產(chǎn)品大幅提升性能的必要特征。

  不過,AMD副總裁兼服務(wù)器工作站業(yè)務(wù)總經(jīng)理Patrick Patla接受采訪時,并沒有明確透露單核多線程技術(shù)的未來,而是繼續(xù)重申已經(jīng)公布的Opteron路線圖:“如果你看一下我們路線圖以及我們在多線程處理器市場的表現(xiàn)就會知道,我們相信每條線程都擁有完整的是目前的選擇。2010年,我們就會推出12核處理器,2011年16核。我們相信未來幾年內(nèi)我們就能夠完善支持48或64線程環(huán)境,讓我們來看看2012到2013年會帶來些什么吧。”

  既然2011年才是16核,那么2012到2013直接跳躍到48甚至64核似乎并不是那么正常。另外,Patrick Patla前面句句都在講“核”,而到了后面又變成了“線程”,似乎就在暗示到時AMD可能會采納單核多線程技術(shù)。
  小結(jié)
  其實多線程編程是一個很有意思也很有用的技術(shù),使用多線程技術(shù)的網(wǎng)絡(luò)螞蟻是目前常用的工具之一,使用多線程技術(shù)的grep比單線程的grep要快上幾倍,類似的例子還有很多。希望大家能用多線程技術(shù)寫出高效實用的好程序來。當(dāng)然發(fā)現(xiàn)多線程的更多用處就更好了。說不定你就會在線程的發(fā)展史上留下你不可磨滅腳印哦。只要努力什么不能實現(xiàn)呢。信息的世界總是在發(fā)現(xiàn)中成長的。你不定就是下一個發(fā)現(xiàn)者呢。

 


  

參考文獻(xiàn):

[1]. arg datasheet http://hbjingang.com/datasheet/arg_2147916.html.


版權(quán)與免責(zé)聲明

凡本網(wǎng)注明“出處:維庫電子市場網(wǎng)”的所有作品,版權(quán)均屬于維庫電子市場網(wǎng),轉(zhuǎn)載請必須注明維庫電子市場網(wǎng),http://hbjingang.com,違反者本網(wǎng)將追究相關(guān)法律責(zé)任。

本網(wǎng)轉(zhuǎn)載并注明自其它出處的作品,目的在于傳遞更多信息,并不代表本網(wǎng)贊同其觀點或證實其內(nèi)容的真實性,不承擔(dān)此類作品侵權(quán)行為的直接責(zé)任及連帶責(zé)任。其他媒體、網(wǎng)站或個人從本網(wǎng)轉(zhuǎn)載時,必須保留本網(wǎng)注明的作品出處,并自負(fù)版權(quán)等法律責(zé)任。

如涉及作品內(nèi)容、版權(quán)等問題,請在作品發(fā)表之日起一周內(nèi)與本網(wǎng)聯(lián)系,否則視為放棄相關(guān)權(quán)利。

廣告
OEM清單文件: OEM清單文件
*公司名:
*聯(lián)系人:
*手機(jī)號碼:
QQ:
有效期:

掃碼下載APP,
一鍵連接廣大的電子世界。

在線人工客服

買家服務(wù):
賣家服務(wù):
技術(shù)客服:

0571-85317607

網(wǎng)站技術(shù)支持

13606545031

客服在線時間周一至周五
9:00-17:30

關(guān)注官方微信號,
第一時間獲取資訊。

建議反饋

聯(lián)系人:

聯(lián)系方式:

按住滑塊,拖拽到最右邊
>>
感謝您向阿庫提出的寶貴意見,您的參與是維庫提升服務(wù)的動力!意見一經(jīng)采納,將有感恩紅包奉上哦!