1. 程式人生 > >執行緒初步(1)—— 執行緒的建立、引數和返回值、結束、狀態、取消

執行緒初步(1)—— 執行緒的建立、引數和返回值、結束、狀態、取消

1執行緒(thread)的概念和特點

  網路一般都需要實現程式碼的並行。程式碼的並行必須藉助多程序/多執行緒。
  主流作業系統中都是支援多程序,而在每個程序的內部,都支援多執行緒並行。

  程序,重量級的,擁有自己獨立的記憶體空間。
  執行緒,輕量級的,不需要擁有自己獨立的記憶體空間,只是額外擁有一個獨立的棧。一個程序記憶體的所有執行緒共享程序的資源(程式碼區、全域性區、堆、檔案目錄……)。
  程序中支援多執行緒並行,其中有一個是主執行緒,程序中必須有主執行緒(main函式)。

  因此網路開發經常是網路+多執行緒模式。

2 執行緒的實現原理

  計算機程式執行的硬體必備:CPU、記憶體。如果要並行,意味著CPU和記憶體都應該可分。記憶體是可分的,但CPU不可分,那麼多執行緒怎麼並行?
  主流作業系統採用CPU時間片技術實現多執行緒的並行。

人的感知是需要時間的,這種時間屬於時間段,比如0.1秒,對於計算機來說,0.1秒可以分為100毫秒。把100毫秒的CPU執行時間分成100個CPU時間片,每個 1毫秒。假如有4個執行緒並行,每個執行緒分1片,4毫秒以後,每個執行緒都運行了1毫秒。針對時間點來說,執行緒沒有並行;針對時間段來說,利用CPU時間片技術可以實現並行。

  多執行緒之間互相獨立,但又互相影響。
  主執行緒一旦結束,程序隨之結束,程序結束導致所有執行緒結束。
  多執行緒之間程式碼是亂序執行,每個執行緒內部的程式碼是順序執行。

3 執行緒的實現

  POSIX規範中對執行緒做了比較完善的定義,因此,執行緒編碼使用 pthread.h,幾乎所有的函式都以pthread_ 開頭。程式碼在libpthread.so中。

  比如:建立執行緒的函式:
  pthread_create()
  4個指標型別做引數:
    第一個引數:用於儲存pthread_t 型別的執行緒ID
    第二個引數: 執行緒屬性,一般為0即可(預設屬性)
    第三個引數和第四個引數聯合使用,第三個引數是函式指標,把執行緒需要執行的程式碼寫在函式中,函式的引數由第四個引數提供。

void* (*fun) (void*)

  返回,成功返回0,失敗返回錯誤碼。執行緒的函式錯誤處理通過返回錯誤碼的方式,而不是使用errno。

#include <stdio.h>
#include <pthread.h>
#include <string.h> void* task(void* p){ int i; for(i=0;i<100;i++){ printf("task:%d\n",i); } } int main(){ pthread_t id;//用來儲存執行緒ID printf("size=%d\n",sizeof(id)); int res = pthread_create(&id,0,task,0); if(res/*!=0*/) printf("create error:%s\n",strerror(res));//執行緒錯誤處理 int i; for(i=0;i<100;i++){ printf("main:%d\n",i); } sleep(1); }

4 執行緒的引數和返回值

4.1 執行緒的引數

  在使用執行緒的引數時,必須保證引數的指向有效。
  pthread_join()可以讓一個執行緒等待另外一個執行緒結束,並且取得結束執行緒的返回值。(類似wait)

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

void* task(void* p){//p就是create()第4個引數
    int* pi = p;
    printf("*pi=%d\n",*pi);
    *pi = 200;
}

//練習:執行緒傳入圓的半徑,列印圓的面積
void* task2(void* p){
    double* pd = p;
    printf("s=%lf\n",3.14*(*pd)*(*pd)); 
}

int main(){
    pthread_t id1,id2,id3;
    int x = 100;
    pthread_create(&id1,0,task,&x);
    id2 = pthread_self();//取當前執行緒的ID
    printf("id1=%u,main=%u\n",id1,id2);
    pthread_join(id1,0); 
    printf("x=%d\n",x);
    double d = 1.0;
    pthread_create(&id3,0,task2,&d);
    pthread_join(id3,0);
}
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>

void* task(void* p){
    int x = (int)p;//可以拿指標當int用
    printf("x=%d\n",x);  
}

void* task2(void* p){
    sleep(1); 
    int* pi = p;//p已經被釋放,無效
    printf("*pi=%d\n",*pi);
}

int main(){
    pthread_t id1,id2;
    int x = 100;
    pthread_create(&id1,0,task,(void*)x);//傳int
    pthread_join(id1,0);
    int* pi = malloc(4); *pi = 100;
    pthread_create(&id2,0,task2,pi);
    free(pi); pthread_join(id2,0);
}

4.2 執行緒的返回值

關於函式/執行緒的返回值:
  1 不能直接以陣列做返回型別;
  2 能返回區域性變數,但不能返回指向區域性變數的指標;
  3 加了static的變數指標可以返回。

  執行緒的返回值必須是一個有效的指標:全域性變數、常量、傳入的指標、static的區域性變數。
  執行緒的返回值可以pthread_join的第二個引數取得:
    pthread_join(pthread_t id,void** retval)
  取返回值時,相當於程式碼:
    *(retval) = 執行緒的返回值

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

void* task(void* p){
    printf("%s\n",(char*)p);
    //p = "hello";//改地址,p指向只讀常量區
    strcpy(p,"hello");//沒有改地址main()有效
    //char st[] = "hello";//區域性變數,返回無效
    //return st;
    return p;//res = p;
}

//練習:線上程中計算1-10的和,並返回給main
void* task2(void* p){
    /*static*/ int sum = 0;
    int i;
    for(i=1;i<11;i++){
        sum = sum+i;
    }
    return (void*)sum;//&sum; 
}

int main(){
    char str[] = "abcde"; pthread_t id;
    pthread_create(&id,0,task,str);
    char* res;//res是 野指標
    pthread_join(id,(void**)&res);//res = p;
    printf("res=%s\n",res);
    pthread_create(&id,0,task2,0);
    //int* pi;
    //pthread_join(id,(void**)&pi);
    //printf("*pi=%d\n",*pi);
    int x;
    pthread_join(id,(void**)&x);
    printf("x=%d\n",x);
}

5 執行緒的結束

正常結束:
  執行緒函式結束
  pthread_exit(void* retval),與return一樣
非正常結束:
  出錯/被其他執行緒取消
注:exit()結束的是程序,所以不能用於結束執行緒。

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

void* task(void* p){
    int i;
    for(i=0;i<100;i++){
    //if(i == 12)  return (void*)i;
    //if(i == 12) pthread_exit((void*)i);
    if(i == 12) exit(i);//結束程序
    } 
}

int main(){
    pthread_t id;
    pthread_create(&id,0,task,0);
    int res;
    pthread_join(id,(void**)&res);
    printf("res=%d\n",res);
}

6 執行緒的狀態

執行緒在啟動後,可以通過不同的函式進入不同的狀態:
  pthread_join() 進入非分離狀態(同步),非分離狀態的執行緒會在pthread_join()結束後回收執行緒資源。
  pthread_detach() 進入分離狀態(非同步),分離狀態的執行緒會線上程結束後直接回收執行緒的資源。
  已經處於分離狀態的執行緒 join()沒有效果。執行緒最好處於這兩種狀態其中的一種。

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

void* task(void* p){
    int i;
    for(i=0;i<10;i++){
        printf("task:%d\n",i); usleep(100000);
    }
}

int main(){
    pthread_t id;
    pthread_create(&id,0,task,0);
    pthread_detach(id);
    pthread_join(id,0);
    int i;
    for(i=0;i<10;i++){
        printf("main:%d\n",i); usleep(100000);
    }
}

7 執行緒的取消(瞭解)

  執行緒的取消就是給目標執行緒發CANCEL訊號,目標執行緒可以做出3種選擇:忽略、立刻停止、過一會再停止。
  執行緒取消的相關函式:
    pthread_cancel() 給目標執行緒發取消訊號
    pthread_setcancelstate() 設定是否支援取消
    pthread_setcanceltype() 設定取消的方式

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

void* task1(void* p){
    //pthread_setcancelstate(//不能取消
    //PTHREAD_CANCEL_DISABLE,0);
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
    //pthread_setcanceltype(//立即取消
        //PTHREAD_CANCEL_ASYNCHRONOUS,0);
    pthread_setcanceltype(//到下一個取消點
        PTHREAD_CANCEL_DEFERRED,0);
    while(1) 
        printf("-----------\n"),usleep(1);
}

void* task2(void* p){
    sleep(3);
    printf("取消執行緒1\n");
    pthread_cancel(*(pthread_t*)p);
}

int main(){
    pthread_t id1,id2;
    pthread_create(&id1,0,task1,0);
    pthread_create(&id2,0,task2,&id1);
    pthread_join(id1,0); pthread_join(id2,0);
}

相關推薦

執行初步1—— 執行建立引數返回結束狀態取消

1執行緒(thread)的概念和特點   網路一般都需要實現程式碼的並行。程式碼的並行必須藉助多程序/多執行緒。   主流作業系統中都是支援多程序,而在每個程序的內部,都支援多執行緒並行。   程序,重量級的,擁有自己獨立的記憶體空間。   執行緒,輕量

Java多執行程式設計-1-執行安全鎖Synchronized概念

一、程序與執行緒的概念 (1)在傳統的作業系統中,程式並不能獨立執行,作為資源分配和獨立執行的基本單位都是程序。 在未配置 OS 的系統中,程式的執行方式

第11章——《執行1

實驗環境介紹 gcc:4.8.5 glibc:glibc-2.17-222.el7.x86_64 os:Centos7.4 kernel:3.10.0-693.21.1.el7.x86_64 執行緒概念 忽略(ps:Linux是用程序實

執行學習1

優點:多程序,多執行緒可以讓程式不被阻塞.可以充分利用多核cpu的優勢,提高執行效率 建立方式:   (1)通過繼承Thread類,並重寫其中的run方法來出建立 Thread t = new Thread() { public void run() { // 執行 //

java多執行知識1

基礎概念 1.執行緒和程序: 程序有自己的獨立空間,而執行緒共享程序的空間 執行緒通訊方便,同一程序的執行緒共享全域性變數,靜態資料 多程序更健壯,多執行緒只要有一個執行緒死掉,整個程序也死 2.同步和非同步:同步必須等該方法的呼叫返回 3.並行和

JVM除錯常用命令——jstack命令與Java執行1

1 jstack 命令 jstack命令的主要作用是列印指定Java程序中每一個執行緒的工作狀態,以及每個執行緒棧當前的方法執行順序等詳細情況。為什麼jstack命令不和jmap、jinfo、jstat等命令一同講解,而要單獨成文呢?因為通過jstack命令給出的執行緒棧詳細情況,可

執行基礎1

概念 執行程式會建立一個程序。是OS排程的最小單元是執行緒(輕量級程序)。 普通的java程式包含的執行緒: 11:Monitor Ctrl-Break //監聽中斷訊號 5:Attach Listener //獲取記憶體dump,執行緒dump 4:Signal Dispatcher /

java執行複習1

Java 程序與執行緒的對比 程序是資源分配的最小單位,執行緒是程式執行的最小單位,是系統獨立排程和分派 CPU 的基本單位 程序有自己的獨立地址空間,每啟動一個程序,系統就會為它分配地址空間,建立資料表來維護程式碼段、堆疊段和資料段,這種操作非常昂貴。而執行緒是共享程序中

C++ 多執行框架1:new 一下就啟動一個執行

幾年前寫過一個C++的多執行緒框架,雖然寫完了,但是人一懶做了一次說明以後就沒影了,最近把程式碼整理了一下,準備發到github上,在這裡,再把這個框架總結一下吧。 多執行緒一直是程式設計中常見的問題,特別是在Linux的c++上,多執行緒的封裝一直不是很好,當然,

java 執行1

ThreadPoolExecutor概述         ThreadPoolExecutor 下文簡稱 TPE ,我們使用它都是從Executror 這個類中的方法 : 1 public static Executo

執行學習1

建立執行緒 執行緒是一條獨立的執行流,有自己的程式執行計數器,有自己的棧。 Java中建立執行緒有兩種方式: 一種是繼承Thread,另外一種是實現Runnable介面. 繼承Thread類: public class HelloThread extends Thread {

執行1-執行的終止方法

前言        近期看了一本關於多執行緒的書籍《Java多執行緒程式設計核心技術》。下面對學習到的關於執行緒的終止方法進行總結,如果有錯誤歡迎大家指出,如果對大家有幫助,歡迎轉載和點贊。 概述      java中

執行初步

今天我們將通過執行緒來談一談生產者消費者的問題 首先我們寫一個小程式生產一個商品並消費一個商品 /** * 寫一個商品者生產消費者消費的執行緒小程式 * @author lover * */ class goods{ private i

java併發程式設計 執行安全1

最近想了解併發程式設計,二執行緒安全是它的基礎。所以看了下java相關的執行緒安全知識。 執行緒安全的核心是程式碼正確性(一般是輸出的結果); 首先無狀態的物件是執行緒安全的;因為一個無狀態的物件即不包含其他域;也沒有對其他域的引用; (1)原子性    原子性:即程式碼不

Java多執行學習1——停止執行

目錄: 1.interrupt方法學習(基礎知識) 2.異常法 3.sleep法 4.return法 5.stop法(不推薦) 1.interrupt方法學習(基礎知識) 呼叫interrupt方法只是對執行緒做了一個標記(停止標記),並沒有停止執行緒的效果,需要結合以下

併發1--執行池簡介

    通常情況下,當我們使用一個執行緒的時候,採用new方式去建立一個執行緒,這樣實現起來很方便,但是與此同時存在一個問題:大量建立執行緒,會帶來資源的消耗,並且如果併發的數量很多的時候,並且每個執

執行開發1:主執行,前臺執行,後臺執行,守護執行,子執行,託管執行的關係

1.主執行緒 當一個程式啟動時,就有一個程序被作業系統(OS)建立,與此同時一個執行緒也立刻執行,該執行緒通常叫做程式的主執行緒(Main Thread),因為它是程式開始時就執行的,如果你需要再建立執行緒,那麼建立的執行緒就是這個主執行緒的子執行緒。每個程序至少都有一個

學習使用chromium裡的執行1

          Chromium就好比是一個寶藏,裡面有很多寶貝。其中我最喜歡的寶貝是base庫和ipc(程序間通訊) 。這兩件寶貝在大型專案開發中會給我們帶來極大的幫助。所以值得我們去花大功夫研究、學習的。在來到我現在所在的公司前,我對chromium的瞭解幾乎沒有,

執行初步---join,yield

今天我們來學習一下執行緒裡面的兩個方法 一、join(); join方法:等待執行緒終止。 使用方法 執行緒名.join(); 表示的是當前執行緒加入,當新加入的執行緒加入,原先的執行緒才會開始執行,接下來我們寫一個小程式來演示一

netty原始碼分析之-EventLoop與執行模型1

執行緒模型確定來程式碼的執行方式,我們總是必須規避併發執行可能會帶來的副作用,所以理解netty所採用的併發模型的影響很重要。netty使用了被稱為事件迴圈的EventLoop來執行任務來處理在連線的生命週期內發生的事件 執行緒模型 對於Even