1. 程式人生 > >linux執行緒學習(2)

linux執行緒學習(2)

執行緒的生命週期

1、當c程式執行時,首先執行main函式。線上程程式碼中,這個特殊的執行流被稱作初始執行緒或者主執行緒。你可以在初始執行緒中做任何普通執行緒可以做的事情。
2、主執行緒的特殊性在於,它在main函式返回的時候,會導致程序結束,程序內所有的執行緒也將會結束。這可不是一個好的現象,你可以在主執行緒中呼叫pthread_exit函式,這樣程序就會等待所有執行緒結束時才終止。
3、主執行緒接受引數的方式是通過argc和argv,而普通的執行緒只有一個引數void*

int main(int argc, char const *argv[])

4、在絕大多數情況下,主執行緒在預設堆疊上執行,這個堆疊可以增長到足夠的長度。而普通執行緒的堆疊是受限制的,一旦溢位就會產生錯誤

執行緒的四個基本狀態

  • 就緒:當執行緒剛被建立時就處於就緒狀態,或者當執行緒被解除阻塞以後也會處於就緒狀態。就緒的執行緒在等待一個可用的處理器,當一個執行的執行緒被搶佔時,它立刻又回到就緒狀態
  • 執行:當處理器選中一個就緒的執行緒執行時,它立刻變成執行狀態
  • 阻塞:執行緒會在以下情況下發生阻塞:試圖加鎖一個已經被鎖住的互斥量,等待某個條件變數,呼叫singwait等待尚未發生的訊號,執行無法完成的I/O訊號,由於記憶體頁錯誤
  • 終止:執行緒通常啟動函式中返回來終止自己,或者呼叫pthread_exit退出,或者取消執行緒

執行緒基本控制

  • 執行緒終止:
    • 如果程序中的任意一個執行緒呼叫了exit,_Exit,_exit,那麼整個程序就會終止
    • 普通的單個執行緒有一下3中方式退出,這樣不會終止程序
      (1)從啟動例程中返回,返回值是執行緒的退出碼
      (2)執行緒可以被同一程序中的其他執行緒取消
      (3)執行緒呼叫pthread_exit(void *rval)函式,rval是退出碼
  • 執行緒連線:
    • int pthread_join(pthead_t tid, void **rval)
      呼叫該函式的執行緒會一直阻塞,直到指定的執行緒tid呼叫pthread_exit、從啟動例程返回或者被取消
      引數tid就是指定執行緒的id
      引數rval是指定執行緒的返回碼,如果執行緒被取消,那麼rval被置為PTHREAD_CANCELED
      該函式呼叫成功會返回0,失敗返回錯誤碼
      為什麼要連線執行緒:如果不連線執行緒,會導致執行緒資源無法釋放,也不能被複用,造成資源的洩露。還有就是利用連線使用執行緒退出的返回值,得知退出狀態
    • 呼叫pthread_join會使指定的執行緒處於分離狀態,如果指定執行緒已經處於分離狀態,那麼呼叫就會失敗
      pthread_detach可以分離一個執行緒,執行緒可以自己分離自己
      int pthread_detach(pthread_t thread);
      成功返回0,失敗返回錯誤碼
      為什麼需要分離:在預設的情況下,新建立的執行緒處於可連線狀態,執行緒退出後需要對它進行連線操作,否則造成資源洩露,如果其他執行緒並不關心執行緒的還回值,進行連線就是一種負擔,因此有了讓執行緒退出後,系統進行給我們釋放執行緒的資源,無需進行連線釋放,這就是執行緒分離的作用
  • 執行緒取消:

    • int pthread_cancel(pthread_t tid)
      取消tid指定的執行緒,成功返回0。但是取消只是傳送一個請求,並不意味著等待執行緒終止,而且傳送成功也不意味著tid一定會終止

    • 取消狀態,就是執行緒對取消訊號的處理方式,忽略或者響應。執行緒建立時預設響應取消訊號int pthread_setcancelstate(int state, int *oldstate)
      設定本執行緒對Cancel訊號的反應,state有兩種值:PTHREAD_CANCEL_ENABLE(預設)PTHREAD_CANCEL_DISABLE,
      分別表示收到訊號後設為CANCLED狀態和忽略CANCEL訊號繼續執行;old_state如果不為NULL則存入原來的Cancel狀態以便恢復

    • 取消型別:取消型別,是執行緒對取消訊號的響應方式,立即取消或者延時取消。執行緒建立時預設延時取消
      int pthread_setcanceltype(int type, int *oldtype)
      設定本執行緒取消動作的執行時機,type由兩種取值:PTHREAD_CANCEL_DEFFERED和PTHREAD_CANCEL_ASYCHRONOUS,僅當Cancel狀態為Enable時有效,分別表示收到訊號後繼續執行至下一個取消點再退出和立即執行取消動作(退出);oldtype如果不為NULL則存入運來的取消動作型別值。
    • 取消點:取消一個執行緒,它通常需要被取消執行緒的配合。執行緒在很多時候會檢視自己是否有取消請求
      如果有就主動退出, 這些檢視是否有取消的地方稱為取消點
      很多地方都是包含取消點,包括
      pthread_join()、 pthread_testcancel()、pthread_cond_wait()、 pthread_cond_timedwait()、sem_wait()、sigwait()、write、read,大多數會阻塞的系統呼叫,在linux中man pthreads檢視取消點函式。

例項

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
void * pthread_func(void *arg)
{
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);//set pthread's state ,can't cancel
    printf("i am new pthread\n");
    sleep(4);
    printf("set the new pthread be can cancel\n");
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
    //pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);//情況二:第二次也設定為執行緒不能被取消。
    //pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);//情況三:將這裡取掉登出,就變成立即取消
    printf("i am the first point of cancel\n");
    printf("i am the second point of cancel\n");
    return (void *)0;//如果是正常的退出,還回值為0
}

int main()
{
    pthread_t pid;
    int err;
    void *val;//new pthread return value

    err=pthread_create(&pid,NULL,pthread_func,NULL);//create a new pthread
    if(err!=0)
    {
        printf("create new pthread failed\n");
        return -1;
    }
    sleep(2);

    pthread_cancel(pid);//取消新執行緒
    pthread_join(pid,&val);//join the new pthread,nutil new pthread over;
    printf("new pthread return val=%d\n",(int *)val);//列印0,正常退出,列印為-1時,說明新執行緒是被取消退出的。

    return 0;
}

1
這裡寫圖片描述

2、把情況二處註釋取掉
這裡寫圖片描述
3、把情況二處註釋、情況三處註釋取掉
這裡寫圖片描述

  • 向執行緒傳送訊號:int pthread_kill(pthread_t thread, int sig);
    是向執行緒傳送signal。大部分signal的預設動作是終止程序的執行,所以,我們才要用sigaction()去抓訊號並加上處理函式。
    向指定ID的執行緒傳送sig訊號,如果執行緒程式碼內不做處理,則按照訊號預設的行為影響整個程序,也就是說,如果你給一個執行緒傳送了SIGQUIT,但執行緒卻沒有實現signal處理函式,則整個程序退出。
    如果要獲得正確的行為,就需要線上程內實現sigaction了。
    所以,如果int sig的引數不是0,那一定要清楚到底要幹什麼,而且一定要實現執行緒的訊號處理函式,否則,就會影響整個程序。
    如果int sig是0呢,這是一個保留訊號,其實並沒有傳送訊號,作用是用來判斷執行緒是不是還活著。
  • 清除操作:執行緒可以安排它退出時的清理操作,這與程序的可以用atexit函式安排程序退出時需要呼叫的函式類似。這樣的函式稱為執行緒清理處理程式。執行緒可以建立多個清理處理程式,處理程式記錄在棧中,所以這些處理程式執行的順序與他們註冊的順序相反
    pthread_cleanup_push(void (rtn)(void), void *args)//註冊處理程式
    pthread_cleanup_pop(int excute)//清除處理程式
    當執行以下操作時呼叫清理函式,清理函式的引數由args傳入
    1、呼叫pthread_exit
    2、響應取消請求
    3、用非零引數呼叫pthread_cleanup_pop

練習

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
void clean_first(void *arg)
{
    printf("%s first clean\n",(char *)arg );

}
void clean_second(void *arg)
{
    printf("%s second clean\n", (char *)arg);


}

void *pthread_func1(void *arg)
{
    printf("this is new pthread1\n");
    pthread_cleanup_push(clean_first,"pthread1");
    pthread_cleanup_push(clean_second,"pthread1");

    pthread_cleanup_pop(1);
    pthread_cleanup_pop(0);

    return (void *)1;
}

void *pthread_func2(void *arg)
{
    printf("this is new pthread2\n");
    pthread_cleanup_push(clean_first,"pthread2");
    pthread_cleanup_push(clean_second,"pthread2");
    pthread_exit((void *)2);
    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);


}

int main()
{
    pthread_t pid;
    int err;
    err = pthread_create(&pid,NULL,pthread_func1,NULL);
    if(err!=0)
    {
        printf("create first new pthread failed\n");
        return -1;
    }
    err = pthread_create(&pid,NULL,pthread_func2,NULL);
    if(err!=0)
    {
        printf("create second new pthread failed\n");
        return -2;
    }
    sleep(5);

    return 0;
}

結果:
這裡寫圖片描述

相關推薦

linux執行學習2

執行緒的生命週期 1、當c程式執行時,首先執行main函式。線上程程式碼中,這個特殊的執行流被稱作初始執行緒或者主執行緒。你可以在初始執行緒中做任何普通執行緒可以做的事情。 2、主執行緒的特殊性在於,它在main函式返回的時候,會導致程序結束,程序內所有的執

執行學習2

ReentrantLock 的一些方法 參考知乎關於lockInterruptibly用法 參考這位博主的多執行緒文章 getHoldCount() 方法:查詢當前執行緒保持此鎖定的個數,也就是呼叫 lock() 的次數;請注意這是當前執行緒鎖定的次數 getQueueLength

linux執行學習3

執行緒的同步 1. 互斥量 為什麼要使用互斥量: 當多個執行緒共享相同的記憶體時,需要每一個執行緒看到相同的檢視。當一個執行緒修改變數時,而其他執行緒也可以讀取或者修改這個變數,就需要對這些執行緒同步,確保他們不會訪問到無效的變數 互斥鎖的初始化和銷燬:

Linux執行學習pthread_key_create

函式 pthread_key_create() 用來建立執行緒私有資料。該函式從 TSD 池中分配一項,將其地址值賦給 key 供以後訪問使用。第 2 個引數是一個銷燬函式,它是可選的,可以為 NULL,為 NULL 時,則系統呼叫預設的銷燬函式進行相關的資料登出。如果不為空

linux執行學習——實現“生產者和消費者”

在上一篇文章中,利用訊號量實現了執行緒間的互斥,這一篇將要利用訊號量的互斥同步機制來實現一個經典例項,就是“生產者和消費者”。 1、簡單描述生產者和消費者的問題。 有一個緩衝區和兩個執行緒:生產者和消費者。生產者把產品放入緩衝區,而消費者從緩衝區中拿走。當緩衝區滿時,生產者必

Linux-C執行學習入門

下面兩個仁兄總結非常好。 主要學習一個例子: /* * test1.c * * Created on: 2016年7月26日 * Author: Andy_Cong

第11章——《執行2

實驗環境介紹 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 執行緒同步 執行緒同步解決的問題:同一個執行

執行學習1

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

執行學習

問題 1.賣票系統(如果每個執行緒執行的程式碼相同,可以使用同一個Runnable物件,這個Runnable物件中有那個共享資料) 解決 public class MultiThreadShareDataStudy { public static void main(String

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

(接上文《JVM除錯常用命令——jstack命令與Java執行緒棧(1)》) 1.2、jstack中的執行緒關鍵資訊 上一篇文章中我們介紹了jstack命令的基本使用,也列舉了一個比較簡單的示例。雖然之前的文章內容中沒有介紹查詢結果中的一些關鍵資訊,但是這並不影響什麼。本片文章中

Java多執行學習:AQS 原理以及 AQS 同步元件總結

常見問題:AQS 原理?;CountDownLatch和CyclicBarrier瞭解嗎,兩者的區別是什麼?用過Semaphore嗎? 本節思維導圖: 阿里雲產品 1888 代金券領取:https://promotion.aliyun.com/ntms

Java多執行學習JUC 中的 Atomic 原子類總結

阿里雲產品 1888 代金券領取:https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=hf47liqn 本節思維導圖: 1 Atomic 原子類介紹 Atomic 翻譯成中文是原

執行學習執行的互斥

生產者與消費者模型 在講同步和互斥之前,首先了解一下消費者模型 什麼是消費者模型? 消費者模型是一個描述消費者和生產者之間的關係的一個模型,生產者和消費者模型指的是在一個場所中,兩個角色,三種關係 消費者和消費者之間——互斥 消費者之間是競爭關係,比如有一個

執行學習4:三種實現Java多執行的方法:Thread、Callable和Runable 的比較與區別

2018年10月03日 目錄 前言 前言 JVM允許應用程式併發執行多執行緒:最常用的是兩個方法:(1)基礎Thread類,重寫run()方法;(2)或實現Runnable 介面,實現介面的run()方法;(3)另外一種方法是:實現callable 介面

執行學習5:synchronized 的基礎使用

2018年10月03日 目錄 前言 前言 java中已經有了內建鎖:synchronized,synchronized的特點是使用簡單,一切交給JVM去處理,不需要顯示釋放; j

執行學習3

執行緒池 為了避免系統頻繁的建立和銷燬執行緒,我們可以將建立的執行緒進行復用。資料庫中的資料庫連線池也是此意。以下是執行緒池的優點 簡書執行緒池的使用細節 阿里巴巴外掛安裝說明 降低資源消耗。通過重複利用已建立的執行緒降低執行緒建立和銷燬造成的消耗。 提高響應速度。當任務到達時,任

C++ 多執行框架 2:Mutex 互斥和 Sem 訊號量

互斥和訊號量是多執行緒程式設計的兩個基礎,其原理就不詳細說了,大家去看看作業系統的書或者網上查查吧。 對於互斥的實現,無論什麼作業系統都離不開三個步驟 1.初始化互斥鎖 2.鎖操作 3.解鎖操作 對於不同的系統只是實現的函式有一些不同而已,但是功能其實都大同小異,在

Java多執行程式設計-2-可重入鎖以及Synchronized的其他基本特性

原文出自 : https://blog.csdn.net/xlgen157387/article/details/78005352 一、Synchronized鎖重入 (1)關鍵字Synchronized擁有鎖重入的功能,也就是在使用Synchronized的時候,當一

Java CompletableFuture組合拼裝非同步執行任務2

Java CompletableFuture組合拼裝非同步執行緒任務 private void seq() throws ExecutionException, InterruptedException { System.out.println("時間1:"

執行學習——控制執行

Java裡提供了一些工具方法,通過這些方法可以很好地控制執行緒的執行。1、join執行緒        Thread提供了讓一個執行緒等待另一個執行緒完成的方法——join()方法。當在某個程式執行流中呼叫其他執行緒的join()方法時,呼叫執行緒將被阻塞,直到被join()