1. 程式人生 > >執行緒控制(一)

執行緒控制(一)

執行緒的優勢

多程序與多執行緒

多程序,每個程序都有自己獨立的地址空間;多執行緒,同一程序內的執行緒共享程序的地址空間。所以建立一個就要耗費時間來為其分配系統資源,而建立一個新執行緒花費的時間會少很多。

程序地址空間獨立而執行緒共享地址空間,執行緒的切換速度遠快於程序的切換速度

程序間資料空間相對獨立,彼此間通訊要以專門的通訊方式進行,通訊時必須經過作業系統。而同一程序內的多個執行緒共享資料空間,一個執行緒的資料可以直接提供給其他執行緒使用。程序間通訊更加方便和省時。

綜上,執行緒節約時間和資源

此外,執行緒可以提高程式的響應速度,可以提高多處理器的效率,可以改善程式的結構

ps:編寫linux下的多執行緒應用程式,需要標頭檔案pthread.h,連結時需要使用庫libpthread.a

gcc ×××.c -lpthread

執行緒的建立

pthread_create

#include<pthread.h>
int pthread_create(pthread_t *thread,pthread_attr_t * attr,
                void* (*start_routine)(void *),void *arg);
pthread_t pthread_self(void) //獲取本執行緒的ID
int pthread_equal(pthread_t thread1,pthread_t thread2).//判斷兩個執行緒ID是否指向同一執行緒
int pthread_once(pthread_once_t *once_control,void(* init_routine)(void)) //用來保證init_routine執行緒函式在程序中僅執行一次

pthread_create

thread:一個指標,執行緒建立成功時,用來返回建立執行緒的ID
attr:該引數用於指定執行緒屬性,NULL表示預設屬性,可以瞭解,需要用再查
start_routine:一個函式指標,指向執行緒建立後要呼叫的函式;這個被執行緒呼叫的函式也叫做執行緒函式。
arg:該函式指向傳遞給函式的引數
注意:建立成功,函式返回0;若不為0則說明建立執行緒失敗。

執行緒的終止

1.通過return從執行緒函式返回
2.呼叫函式pthread_exit()使執行緒退出
3.呼叫pthread_cancel函式取消執行緒

在主執行緒中,如果從main函式返回或是呼叫exit函式退出主執行緒,則整個程序將終止,則整個程序終止,程序內的其他執行緒也會終止。若呼叫pthread_exit()函式,則僅僅是主線程序消亡,程序不會結束,其它執行緒也不會終止,直到所有執行緒結束,程序才會結束。

當程序要使用臨界資源時,要提出請求,如果該資源未被使用則申請成功,否則等待。臨界資源使用完畢後要釋放以便其它執行緒使用。

臨界資源為一個執行緒獨佔,當一個執行緒終止時,如果不釋放其佔有的臨界資源,則該資源會被認為還被已經退出的執行緒所使用,因而永遠不會得到釋放,如果一個執行緒在等待使用這個臨界資源,有可能無限制的等待,就形成來死鎖。

利用pthread_cleanup_push(),pthread_cleanup_pop()函式可以自動釋放資源

從pthread_cleanup_push()的呼叫點到pthread_cleanup_pop()之間的程式段中的終止動作(包括呼叫 pthread_exit()和取消點終止)都將執行pthread_cleanup_push()所指定的清理函式。

採用先入後出的棧結構管理,void routine(void *arg)函式在呼叫pthread_cleanup_push()時壓入清理函式棧,多次對pthread_cleanup_push()的呼叫將在清理函式棧中形成一個函式鏈,在執行該函式鏈時按照壓棧的相反順序彈出。execute引數表示執行到pthread_cleanup_pop()時是否在彈出清理函式的同時執行該函式,為0表示不執行,非0為執行;這個引數並不影響異常終止時清理函式的執行。

#include<pthread.h>
#define pthread_cleanup_push(routine,arg) \
{
    struct _pthread_cleanup_buffer buffer; \
           _pthread_cleanup_push(&buffer,(routine),(srg))\
#define pthread_clean_pop \
        _pthread_cleanup_pop(&buffer,(exeute));
}

pthread_cleanup_push((void *)pthread_mutex_unlock, (void *) &mut);
pthread_mutex_lock(&mut);
/* do some work */
pthread_mutex_unlock(&mut);
pthread_cleanup_pop(0);

本來do some work之後是有pthread_mutex_unlock(&mut);這句,也就是有解鎖操作,但是在do some work時會出現非正常終止,那樣的話,系統會根據pthread_cleanup_push中提供的函式,和引數進行解鎖操作或者其他操作,以免造成死鎖!

**attention:**pthread_cleanup_push()有’{‘,pthread_cleanup_pop()中有’}’,所以這兩個函式要成對出現

一般情況下,程序中各個執行緒的執行是獨立的,執行緒的終止不會相互通知,也不會影響其他執行緒,終止程序的所佔有的資源不會隨著執行緒的終止歸還系統,仍為執行緒所在的程序擁有。

#include<pthread.h>
void pthread_exit(void * retval)
int pthread_join(pthread_t th,void * thread_return);
int pthread_detach(pthread_t th);

pthread_join()的呼叫者被掛起並等待th執行緒終止,如果thread_return不為NULL,則 *thread_return=retval,一個執行緒僅允許一個執行緒使用pthread_join等待它終止,並且被等待的程序應該處於可join狀態,即非DETACHED。(如果有多個程序等待,第一個接受訊號的成功返回,其餘返回錯誤程式碼ESRCH)

一個可join的執行緒所佔的記憶體僅當有執行緒對它執行pthread_join()後才會釋放,
所以為了避免記憶體洩漏,所有執行緒終止時,要嘛已被設定為DETACHED,要嘛使用pthread_join()來回收資源。

pthread_cancel:來自其他執行緒的一個請求

但是如果子執行緒在某個操作被阻塞,等待它的執行緒會無限制的等待,形成死鎖。為了更安全地使執行緒退出,主執行緒通過pthread_cancel函式來請求取消同一程序中的其他執行緒,再呼叫pthread_join等待指定執行緒退出。

注:當主執行緒呼叫pthread_cancel後,只是將取消請求傳送給指定執行緒, 成功呼叫不能保證指定執行緒已經退出,需要呼叫pthread_join等待指定執行緒完全退出,再進行相關資源的釋放。

可取消狀態:當執行緒處於PTHREAD_CANCEL_ENABLE,收到cancel請求會使該執行緒退出執行;反之,若處於PTHREAD_CANCEL_DISABLE,收到的cancel請求將處於未決狀態,執行緒不會退出。執行緒預設可取消狀態為PTHREAD_CANCEL_ENABLE,可通過pthread_setcanceltype修改可取消型別。

可取消型別:當處於PTHREAD_CANCEL_DEFERRED,執行緒在收到cancel請求後,需要執行到取消點才能退出執行;如果處於PTHREAD_CANCEL_ASYNCHRONOUS,可以在任意時間取消,只要收到cancel請求即可馬上退出。執行緒啟動時預設可取消型別為PTHREAD_CANCEL_DEFERRED,可通過pthread_setcanceltype修改可取消型別。

取消點:執行緒檢查是否被取消並按照請求進行動作的一個位置。

一般來說,為了防止資源未被釋放時,執行緒就已經退出。將獲取臨界資源-釋放臨界資源之間的程式碼塊都設定成PTHREAD_CANCEL_DISABLE狀態,其餘的程式碼塊都設定成PTHREAD_CANCEL_ENABLE狀態,確保執行緒在安全的地方退出。如果在可以安全退出的程式碼塊不存在取消點系統呼叫,可以呼叫pthread_testcancel函式自己新增取消點。

執行緒中的私有資料

程序中內的所有執行緒共享程序的資料空間,因此全域性變數為所有執行緒共有,在程式設計時有時需要儲存執行緒自己的全域性變數,這種變數僅在某個執行緒的內部有效。這時就要用到執行緒的私有資料(TSD),線上程內部,執行緒的私有資料可以被各個函式訪問,但它對其它執行緒是遮蔽的。

在使用執行緒的私有資料時,首先要為每個執行緒建立一個相關聯的鍵,一鍵多值,通過鍵來指代執行緒資料。

1、pthread_key_create:建立一個鍵

int pthread_key_create(pthread_key_t *key,void(*destr_function) (void*));
//第二個引數是一個解構函式

首先從linux的TSD池(Thread-specific Data)中分配一項,然後將其值賦給key供以後訪問使用。介面的第一個引數是指向引數的指標,第二引數是函式指標,如果該指標不為空,那麼線上程執行完畢退出時,已key指向的內容為入參呼叫destr_function(),釋放分配的緩衝區以及其他資料。

key被建立之後,因為是全域性變數,所以所有的執行緒都可以訪問。各個執行緒可以根據需求往key中,填入不同的值,這就相當於提供了一個同名而值不同的全域性變數,即一鍵多值。

一鍵多值依靠的一個結構體陣列,即

static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] ={{0,NULL}};

2、pthread_setspecific:為指定鍵值設定執行緒私有資料

int pthread_setspecific(pthread_key_t key, const void *pointer);

該函式將指標pointer的值(指標值而非其指向的內容)與key相關聯,用pthread_setspecific為一個鍵指定新的執行緒資料時,執行緒必須釋放原有的資料用以回收空間。

3、pthread_getspecific:從指定鍵讀取執行緒的私有資料

void * pthread_getspecific(pthread_key_t key);

通過該函式得到與key相關聯的資料

4、pthread_key_delete:刪除一個鍵

void * pthread_getspecific(pthread_key_t key);

該函式用於刪除一個鍵,功能僅僅是將該key在結構體陣列pthread_keys對應的元素設定為“un_use”,與該key相關聯的執行緒資料是不會被釋放的,即是僅僅將鍵刪除,因此執行緒私有資料的釋放必須在釋放鍵之前完成。

相關推薦

執行控制

執行緒的優勢 多程序與多執行緒 多程序,每個程序都有自己獨立的地址空間;多執行緒,同一程序內的執行緒共享程序的地址空間。所以建立一個就要耗費時間來為其分配系統資源,而建立一個新執行緒花費的時間會少很多。 程序地址空間獨立而執行緒共享地址空間,執行緒的切換速

java併發學習--執行

關於java中的執行緒池,我一開始覺得就是為了避免頻繁的建立和銷燬執行緒吧,先建立一定量的執行緒,然後再進行復用。但是要具體說一下如何做到的,自己又說不出一個一二三來了,這大概就是自己的學習習慣流於表面,不經常深入的結果吧。所以這裡決定系統的學習一下執行緒池的相關知識。   自己稍微總結了一下,

java多執行系列:Thread、Runnable、Callable實現多執行的區別

實現多執行緒 java實現多執行緒的方法有三種,分別是繼承thread類,實現runnable介面,實現callable介面(call方法有返回值) /** * 繼承Thread */ public class MyThread extends Thread{ int a = 0;

java多執行-初探

啥是多執行緒?跟程序又是啥關係?   比方說:我去洗手,洗完手去吃飯。 程序(Processor) 洗手跟吃飯是兩個程序。 執行緒(Thread) 在洗手的程序裡,我同時聽歌,還唱歌。那這裡洗手是一個程序,聽歌跟唱歌是兩個執行緒。 在吃飯的程序裡,我同時聽歌,還

執行基礎

最近讀了高洪巖的《Java多執行緒程式設計核心技術》一書,打算記錄下多執行緒的基礎知識點,也算對本書的一個讀後感了。目前打算分四五篇博文進行記錄。 第一篇主要是記錄執行緒的概念,建立,常用的基礎方法等。 1. 什麼是執行緒? 通常我們所說執行緒是程序的最小單位。那麼問題來了,什麼是程序呢?程序就是作業系統結構

程序管理實驗——POSIX下執行控制

實驗目的 1、通過觀察、分析實驗現象,深入理解執行緒及執行緒在排程執行和記憶體空間等方面的特點,並掌握執行緒與程序的區別。 2、掌握在POSIX 規範中pthread_create() 函式的功能和

基本執行同步引言

宣告:本文是《 Java 7 Concurrency Cookbook 》的第二章,作者: Javier Fernández González     譯者:許巧輝 校對:方騰飛 引言 在這個章節中,我們將覆蓋: 同步方法 介紹 在併發程式設計中發生的最常見的一種情況是超過一個

執行管理執行的建立和執行

宣告:本文是《 Java 7 Concurrency Cookbook 》的第一章, 作者: Javier Fernández González 譯者:鄭玉婷 校對:歐振聰 執行緒的建立和執行 在這個指南中,我們將學習如何在Java程式中建立和執行執行緒。與每個Java語言中的元素一樣,執行緒

第四章 執行執行者引言

宣告:本文是《 Java 7 Concurrency Cookbook 》的第四章,作者: Javier Fernández González     譯者:許巧輝     校對:方騰飛 在這個章節中,我們將覆蓋: 執行多個任務並處理所有結果 執行者延遲執行一個任務 執行者週期性地執

執行程式設計——寫一個簡單的死鎖

(整個九月忙著找工作,好多收穫,好多遺憾,最終結局還可以接受,技術路還很遠,再接再厲!面去哪兒網時,寫慣了演算法的我突然讓寫了幾個多執行緒程式設計,有點矇蔽,最近好好整理一下) 死鎖發生的原因: 1、

執行實驗

程式設計實現以下功能: 主執行緒實現以下功能:     定義全域性變數key;     建立兩個執行緒;     如果執行緒正常結束,得到執行緒的結束狀態值,並列印; 執行緒一完成以下操作:  &nb

Linux 多執行程式設計

Linux 多執行緒程式設計 執行緒(Thread)已被許多作業系統所支援,包括Windows/NT ,Linux 以前的多執行緒其實是多程序,而現在意味著一個程序中有多個執行緒 使用多執行緒的原因(多執行緒的優點): 1.“節省”,啟動一個新的程序需要分配給它獨立的地

java-執行

一、為什麼使用執行緒池 重用執行緒池中的使用,減少建立線和銷燬程的的資源消耗和提高效能。 可以對執行緒進行管理與維護 二、執行緒池的建立   執行緒池的建立可以使用Executors類中的方法建立,可以參考常用的四種執行緒池的建立,下面來看J.U.C包下的T

執行學習:多執行的兩種實現方式

程序和執行緒 程序是受作業系統管理的基本執行單元。 執行緒是在程序中獨立執行的子任務。 多執行緒的優點 使用多執行緒技術後,可以在同一時間內執行更多不同種類的任務。 單執行緒是同步執行任務,多執行緒是非同步執行任務。 多執行緒的使用方式 1:繼承Thread 2:實現

Java多執行學習Java多執行入門

Java 併發的基礎知識,可能會在筆試中遇到,技術面試中也可能以併發知識環節提問的第一個問題出現。比如面試官可能會問你:“談談自己對於程序和執行緒的理解,兩者的區別是什麼?” 一 程序和多執行緒簡介 1.1 程序和執行緒 程序和執行緒的對比這一知識點

執行理解  三大特性

程序、執行緒和多執行緒的定義。 程序:是指一段具有某種獨立功能的程式關於某個資料集合的一次執行活動(一段程式的執行過程)。 執行緒:單個程序執行中的每個任務就是一個執行緒。 多執行緒:在一個程序中有多個執行緒共享程序資源,執行任務。 多執行緒的三大特性: 原子性:

java執行 基礎

Thread.java類中的start()方法通知“執行緒規劃器”,此執行緒已準備就緒,等待呼叫執行緒物件的run()方法。這個過程就是讓系統安排一個時間來呼叫Thread中的run()方法,也就是使得執行緒得到執行,啟動執行緒,具有非同步執行的效果。 如果呼叫程式碼的thread.run()就不

Java併發包原始碼學習之執行ThreadPoolExecutor原始碼分析

Java中使用執行緒池技術一般都是使用Executors這個工廠類,它提供了非常簡單方法來建立各種型別的執行緒池: public static ExecutorService newFixedThreadPool(int nThreads) public static ExecutorService

C++多執行系列CreateThread和_beginthreadex區別

現在在學習多執行緒,順便將蒐集到的資料整理下來以供參考和查詢。首先在開始多執行緒學習的時候遇到的首要問題便是多執行緒的建立,在查閱資料後有CreateThread和_beginthreadex兩種方法,可能不止這兩種,以後學習到了再補充。-------------------

android 程序/執行管理----訊息機制的框架

一:android 程序和執行緒 程序是程式執行的一個例項。android通過4大主件,弱化了程序的概念,尤其是在app層面,基本不需要關係程序間的通訊等問題。 但是程式的本質沒有變,尤其是多工系統,以事件為驅動的軟體系統基本模式都是如下: 程式的入口一般是main: 1.初始化: 比如建立視窗,申