一、 線程的概念及優點
線程是進程之中一條執行序列, 一個進程至少有一條執行序列(程),稱之爲主線程, 可以通過庫函數創建新的線程, 稱其爲函數線程。 線程可以同時執行。
優點:提高進程的併發度,並且有效利用多處理器和多核計算器。
二、 線程與進程的區別
(1)線程是輕量級的進程, 進程是資源分配的最小單位, 線程是調度執行的最小單位。 數據共享不同。 在切換時, 線程比進程效率高。
(2)進程是具有一定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。
(3)線程是進程的一個實體,是CPU調度和分配的基本單位,線程自己基本上不擁有系統資源,只擁有一點運行必不可少的資源(如:程序計數器,寄存器和棧),但是它可以與同一個進程的其他線程共享進程所擁有的全部資源。
(4)一個線程可以創建和撤銷另一個線程,同一個進程中多個線程是併發執行。
線程和進程的主要差別在於它們是不同的操作系統資源管理方式,進程有獨立的地址空間,一個進程奔潰後,在保護模式下不會對其他進程產生影響。而線程只是一個進程中的不同執行路徑,線程有自己的堆棧、局部變量,但線程之間沒有單獨的地址空間,一個線程死掉等於整個線程死掉。所以,多進程的程序要比多線程的程序健壯,但進程之間切換時,耗費資源較大,效率要差一些。旦對於一些要求同時進行並且又要共享某些變量的併發操作,只能用線程,不能用進程。
三、 線程的分類
3.1 用戶級: 在用戶空間是多線程的, 內核只識別進程整體。 線程創建、 管理、 銷燬都是由用戶空間負責, 用戶通過調用庫函數在完成。
3.2 內核級: 線程的創建、 控制、 銷燬都是由內核實現的, 每個線程對內核都是可見的。
3.3 組合模型: 一部分是用戶級, 一部分內核級線程。 介於內核級和用戶級之間, 用戶態創建多個線程, 內核看到的也是多個, 只是這是種 m: n 的對應關係
四、 線程的創建
int pthread_create(pthread_t id, pthread_attr_t*attr,void(*pthread_fun)(void), void *arg);
id : 線程的編號, 由系統自動填充;
attr: 線程屬性;
pthread_fun: 線程創建以後所調用的函數地址;
arg: 傳遞給函數線程的參數。
例子:創建兩個進程,一個打印素數,一個對數組排序
void pthread_fun1()
{
int i,j;
int flag=1;
printf("線程1開始打印素數\n");
for(i=2;i<100;i++)
{
for(j=2;j<i;j++)
{
if(i%j==0)
{
flag=0;
break;
}
}
if(flag==1)
{
printf("%d ",i);
}
flag=1;
}
}
void pthread_fun2()
{
int arr[]={12,23,45,65,78,90,98,56,86,32};
int len=sizeof(arr)/sizeof(arr[0]);
int i,j;
printf("線程2選擇排序開始\n");
for(i=0;i<len-1;i++)
{
int min_index=i;
for(j=i+1;j<len;j++)
{
if(arr[min_index]>arr[j])
{
min_index=j;
}
}
if(min_index!=i)
{
int tmp=arr[i];
arr[i]=arr[min_index];
arr[min_index]=tmp;
}
}
for(i=0;i<len;i++)
{
printf("%d ",arr[i]);
}
}
void main()
{
printf("main start\n");
sleep(2);
pthread_t id1,id2;
int res=pthread_create(&id1,NULL,pthread_fun1,NULL);
assert(res==0);
res=pthread_create(&id2,NULL,pthread_fun2,NULL);
}
總結:
1、 pthread_create 函數是庫函數, 編譯的時候必須加載其動態庫。
2、 和寫一個普通函數沒有明顯差別。 只不過在主線程不會調用函數, 而是在創建線程的時候指定函數線程執行的代碼入口地址(即就是函數的地址)。 稱主函數爲住執行序列, 函數的執行爲函數線程執行流。
3、 主線程和函數線程同時執行。 一個進程同時執行多個任務。
五、 線程退出
exit 是結束進程的函數, 主線程要結束, 但是函數線程還在運行, 我們主線程就不能調用 exit 結束, 必須使用: void pthread_exit(void *reval);
六、 線程等待其他線程結束
int pthread_join(pthread_t id, void**p);
作用: 獲取指定線程由 pthread_exit 設置的退出信息。
特性: pthread_join 函數會阻塞直到等待的線程退出。 (類比進程控制中的 wait 函
數)
七、 給函數線程傳遞參數
i. 傳值
將變量的值強轉成 void* , 函數線程中, 對 arg 的值強轉成變量的類型。
ii. 傳地址
將變量的地址強轉成 void*, 函數線程中, 對 arg 的值強轉成變量類型的指針,再去取值。
void *fun1(void *arg)
{
sleep(1);
pthread_t id = *(pthread_t*)arg;
pthread_join(id, NULL);
int i = 0;
printf("線程1開始打印素數\n");
for(i = 2; i < 100; ++i)
{
int j = 2;
for(; j <= i/2; ++j)
{
if(i % j == 0)
{
break;
}
}
if(j > i/2)
{
printf("%d ", i);
}
}
printf("\n");
}
void *fun2(void *arg)
{
int arr[] = {23,12,43,14,76,34,55,93,64,6};
int len = sizeof(arr)/sizeof(arr[0]);
int i = 0, j = 0;
printf("線程2開始排序:\n");
for(; i < len - 1; ++i)
{
int min_index = i;
for(j = i + 1; j < len; ++j)
{
if(arr[j] < arr[min])
{
min_index = j;
}
}
int tmp = arr[min];
arr[min] = arr[i];
arr[i] = tmp;
}
for(i = 0; i < len; ++i)
{
sleep(1);
printf("%d ", arr[i]);
fflush(stdout);
}
printf("\n");
pthread_exit("sort over");
}
void main()
{
pthread_t id1,id2;
int res = pthread_create(&id1, NULL, fun1, (void*)&id2);
assert(res == 0);
res = pthread_create(&id2, NULL, fun2, NULL);
assert(res == 0);
char *p = NULL;
pthread_join(id1, NULL);
//pthread_join(id2,(void**)&p);
//printf("%s\n", p);
printf("main end\n");
}