進程就是運行的程序,是爲了在CPU上實現多道編程而有的概念。但是進程在同一時刻只能幹一件事,如果想同時幹多件事,就要用到線程。線程可以運行在不同的處理器上,從未提高進程的執行效率。
在前面講進程我們知道,進程是一組有序指令、資源、數據的集合,今天要講的線程就是進程內部的一條執行序列(執行流)。每個進程至少有一條執行序列,main函數的執行體。進程可以通過線程創建n條線程,這些新創建的線程稱爲函數線程。main函數所代表的線程爲主線程。
那麼,進程和線程有什麼區別呢?
1、進程是資源分配的最小單位,線程是CPU調度的最小單位(CPU執行的實際上是線程中的指令)。
2、線程是輕量級的進程。
3、管理方式不同:進程是PCB管理,線程由線程結構管理。
線程實現的三種方式:
1、用戶態線程
優點:靈活,在任何操作系統上都可以用;線程切換快;不用修改系統操作,容易實現。
缺點:編程變得複雜,要知道什麼時候讓CPU給別的線程使用;用戶態線程無法完全達到線程提出所要達到的目的:進程級多道編程。
2、內核態線程
優點:用戶操作簡單。
缺點:效率較低;佔用內核態稀缺的資源。
3、混合態線程
用戶態的執行系統負責進程內部線程在非阻塞時切換;內核態的操作系統負責阻塞線程的切換,即我們同時實現內核態和用戶態的線程管理。
線程的創建(線程庫文件的使用):
int pthread_creat(pthread_t *id, pthread_attr_t *attr, void *(*fun)(void*), void *arg);
id 創建出來的線程ID,由於創建之前並不知道,所以先定義pthread_t id,然後傳id地址;
attr 屬性,NULL爲創建默認屬性的線程;
void *(*fun)(void*) 參數類型爲void*的一個函數指針;
arg 就是fun函數的參數。
成功返回0,出錯返回錯誤編碼。
該函數創建的是函數線程。函數線程不同於函數調用,函數調用是這一條執行流中的一部分;函數線程是創建出一條獨立的執行序列,他與主線程同時執行。
包含線程創建的源代碼想要生成可執行文件,必須執行gcc pthread pthread.c -lpthread命令。
線程結束:int pthread_exit(void*);
ptr 可以設置一些退出信息(線程的退出狀態)。進程中的其他線程可以通過pthread_join函數訪問到ptr。
等待線程結束:int pthread_join(pthread_t id, void**);
調用該函數的線程將一直阻塞,等待線程結束,並且可以獲得到等待的線程通過ptr設置的退出信息。void**爲ptr的地址。
取消一個線程:int pthread_cancel(pthread_t thread);
A線程要求B線程終止,通過B線程ID thread,可以請求取消B線程。在接受到取消請求的B線程可以通過函數pthread_setcancelstate設置自己的取消狀態。
int pthread_setcancelstate(int state,int *oldstate);
state:可以是PTHREAD_CANCEL_ENABLE允許線程接收取消請求;或者是PTHREAD_CANCEL_DISABLE忽略取消請求;
oldstate:用於獲取先前的取消狀態。不需要知道時傳NULL就可以。
如果取消請求被接受了,線程可以進入第二個控制層次,用pthread_setcanceltype設置取消類型。
int pthread_setcanceltype(int type,int *oldtype);
type:可以是PTHREAD_CANCEL_ASYNCHRONOUS在接收到取消請求後立刻採取行動,也可以是PTHREAD_CANCEL_DEFERRED在接收到取消請求後,一直等待,直到線程執行了下述函數之一後才採取行動。
pthread_join、pthread_cond_wait、pthread_cond_timedwait、pthread_testcancel、sem_wait或sigwait。
oldtype:可以保存先前的狀態,如果不想知道先前的狀態傳NULL。
默認情況下,線程在啓動時的取消狀態爲PTHREAD_CANCEL_ENABLE,取消類型爲PTHREAD_CANCEL_DEFERRED。
線程函數傳參:
1、將值強轉成void* int a = (int)arg;
該值的類型僅限於char、short、int、long類型。
2、將地址強轉成void* int a = *(int*)arg;
這種方式任何類型都可以,但是如果運行一段時間纔是用參數的值,在這段時間內可能被更改。爲解決該問題,可以在調用pthread_create函數後,先sleep(2),把值傳遞過去後主線程再運行。
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<unistd.h>
#include<pthread.h>
int Ispirmer(int n)//判斷是否是素數
{
int i = 2;
for(;i<n/2;i++)
{
if(n%i == 0)
{
return 0;
}
}
return 1;
}
BubbleSort(int *arr,int len)//冒泡排序
{
int i;
int j;
for(i=0;i<len-1;i++)
{
for(j=0;j<len-1-i;j++)
{
if(arr[j] > arr[j+1])
{
int tmp;
tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
}
void *pthread_fun(void *arg)//函數線程
{
int i = 2;
for(;i<100;i++)
{
if(Ispirmer(i))
{
printf("%d ",i);
}
}
printf("\n");
pthread_exit("hello");
}
int main()
{
pthread_t id;
int ret = pthread_create(&id,NULL,pthread_fun,NULL);
assert(ret == 0);
int arr[] = {2,4,1,7,3,8,4,9,23};
int len = sizeof(arr)/sizeof(arr[0]);
BubbleSort(arr,len);
int i = 0;
for(;i<len;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
char *p = NULL;
pthread_join(id,&p);
}