線程的簡單解析

一、線程基本概念
線程是程序中一個單一的順序控制流程。在單個程序中同時運行多個線程完成不同的工作,稱爲多線程。
線程和進程的區別在於, 子進程和父進程有不同的代碼和數據空間, 而多個線程則共享數據空間,每個線程有自己的執行堆棧和程序計數器爲其執行上下文。多線程主要是爲了節約CPU時間,發揮利用,根據具體情況而定.線程的週期新建就緒運行阻塞死亡線程調度與優先級有線程進入了就緒狀態,需要有線程調度程序來決定何時執行,根據優先級來調度。
線程組每個線程都是一個線程組的一個成員,線程組把多個線程集成一個對象,通過線程組可以同時對其中的多個線程進行操作。在生成線程時必須將線程放在指定的線程組,也可以放在缺省的線程組中,缺省的就是生成該線程的線程所在的線程組.一旦一個線程加入了某個線程組,不能被移出這個組。守護線程是特殊的線程,一般用於在後臺爲其他線程提供服務。
isDaemon():判斷一個線程是否爲守護線程.
setDaemon():設置一個線程爲守護線程.
二、Linux下線程有特點

Linux的線程是通過進程來模擬的,也就是說Linux裏的線程本質上就是進程。

Linux的線程機制是通過內核和庫混合實現的,所以線程的實現在Linux的核心態和用戶態都有執行,內核實現線程/進程的調度,libpthread庫實現線程之間的同步。這也就是爲什麼多線程程序需要連接一個libpthread庫的原因。

Linux程序如果用pthread_create啓動一個新的線程,實際上啓動了兩個輕量進程,第一個是管理線程,第二個纔是真正做事情的線程。但是後續新創建的線程就不需要再創建管理線程了。源碼如下

Linux這種用進程模擬線程的方式,和signal機制不一致,signal是發給進程的,但是在linux裏,往一個進車發送signal,實際上只有一個線程處理這個signal。

Linux的進程機制實現的很好,進程間調度的overhead很小。
三、線程與進程的區別
進程的顆粒度太大,每次都要有上下的調入,保存,調出。如果我們把進程比喻爲一個運行在電腦上的軟件,那麼一個軟件的執行不可能是一條邏輯執行的,必定有多個分支和多個程序段,就好比要實現程序A,實際分成 a,b,c等多個塊組合而成。那麼這裏具體的執行就可能變成:程序A得到CPU =》CPU加載上下文,開始執行程序A的a小段,然後執行A的b小段,然後再執行A的c小段,最後CPU保存A的上下文。這裏a,b,c的執行是共享了A的上下文,CPU在執行的時候沒有進行上下文切換的。這裏的a,b,c就是線程,也就是說線程是共享了進程的上下文環境,的更爲細小的CPU時間段。
線程在進程內部運行(地址空間中),我們可以把一個進程當作是隻有一個線程。
線程的私有: 1. 私有棧結構,保證了線程之間互不干擾。 2. 硬件上下文信息,因爲線程允許被切換,保護了上下文。

四、線程控制
首先介紹我們用到的函數,
1).線程創建 pthread_create,創建成功返回0,失敗返回錯誤號。

#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

2)線程終止
1.return 返回;
2,調用pthread_cancel,源碼如下:

 #include <pthread.h>
int pthread_cancel(pthread_t thread);

3,。調用pthread_exit,代碼如下:

 #include <pthread.h>
void pthread_exit(void *retval);

2) . 線程等待
pthread_join 函數,成功返回0,錯誤返回錯誤號。

#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);

調用該函數的線程將掛起等待,直到id爲thread的線程終止。thread線程以不同的方法終止,通過pthread_join得到的終止狀態也不相同,總結如下:
1.如果thread線程通過return返回,value_ptr存放返回值。
2.如果調用pthread_cancel終止,存放PTHREAD_CANCELED.
3.如果線程自己調用pthread_exit終止自己,存放pthread_exit的參數。

線程控制代碼
1.創建

#include <stdio.h>

void* thread_run(void *arg){
    while(1){
        printf("new thread: tid: %u  pid: %d\n", pthread_self(), getpid());
        sleep(1);
    }

}
int main()
{
    pthread_t id;
    pthread_create(&id, NULL, thread_run, NULL);//線程創建
    while(1){
        printf("main thread: tid: %u  pid: %d\n", pthread_self(), getpid());
        sleep(1);
    }

    return 0;
}

2)線程等待

#include <pthread.h>
#include <stdio.h>


void* thread_run(void* arg){  //線程1
    return (void*)1;
}
void* thread_run1(void *arg){  //線程2
    while(1){
        printf("tid: %d\n", pthread_self());
        sleep(1);
    }
    return NULL;
}

void* thread_run2(void* arg){   //線程3
    pthread_detach(pthread_self());
    printf("sss\n");
}
int main()
{
    pthread_t id;
    pthread_create(&id, NULL, thread_run, NULL); //線程創建
    void* val;
    sleep(3);
    pthread_cancel(id);    //線程終止
    pthread_join(id, &val); //線程等待
    printf("tid: %d, val: %d\n", id, (int)val);

    pthread_create(&id, NULL, thread_run1, NULL);
    sleep(3);
    pthread_cancel(id);
    pthread_join(id, &val);
    printf("tid: %d, id: %d\n", pthread_self(), (int)id);
    printf("tid: %d, val: %d\n", pthread_self(), (int)val);

    pthread_create(&id, NULL, thread_run2, NULL);
    return 0;
}

五、線程分離與結合
在任何一個時間點上,線程是可結合的(joinable),或者是分離的(detached)。一個可結合的線程能夠被其他線程收回其資源和殺死;在被其他線程回收之前,它的存儲器資源(如棧)是不釋放的。相反,一個分離的線程是不能被其他線程回收或殺死的,它的存儲器資源在它終止時由系統自動釋放。
線程的分離狀態決定一個線程以什麼樣的方式來終止自己。在上面的例子中,我們採用了線程的默認屬性,即爲非分離狀態(即可結合的,joinable,需要回收),這種情況下,原有的線程等待創建的線程結束;只有當pthread_join()函數返回時,創建的線程纔算終止,才能釋放自己佔用的系統資源。而分離線程不是這樣子的,它沒有被其他的線程所等待,自己運行結束了,線程也就終止了,馬上釋放系統資源。程序員應該根據自己的需要,選擇適當的分離狀態。
設置線程分離狀態的函數爲
pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
第二個參數可選爲PTHREAD_CREATE_DETACHED(分離線程)和 PTHREAD _CREATE_JOINABLE(非分離線程)。這裏要注意的一點是,如果設置一個線程爲分離線程,而這個線程運行又非常快,它很可能在pthread_create函數返回之前就終止了,它終止以後就可能將線程號和系統資源移交給其他的線程使用,這樣調用pthread_create的線程就得到了錯誤的線程號。要避免這種情況可以採取一定的同步措施,最簡單的方法之一是可以在被創建的線程裏調用pthread_cond_timewait函數,讓這個線程等待一會兒,留出足夠的時間讓函數pthread_create返回。設置一段等待時間,是在多線程編程裏常用的方法。但是注意不要使用諸如wait()之類的函數,它們是使整個進程睡眠,並不能解決線程同步的問題。
另外一個可能常用的屬性是線程的優先級,它存放在結構sched_param中。用函數pthread_attr_getschedparam和函數pthread_attr_setschedparam進行存放,一般說來,我們總是先取優先級,對取得的值修改後再存放回去。
分離線程的好處:
(1) 不用等待;
(2) 有多餘的時間做其他事;
(3) 自動釋放資源。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章