1. 程式人生 > >第12章——《執行緒控制》(1)

第12章——《執行緒控制》(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

執行緒限制

  • 使用sysconf函式可以檢視一些執行緒相關的限制
限制名稱 描述 name引數
DESTRUCTOR_ITERATIONS 執行緒退出時作業系統實現師徒小回縣城特定資料的最大次數 _SC_THREAD_DESTRUCTOR_ITERATIONS
KEYS_MAX 程序可以建立的鍵的最大數目 _SC_THREAD_KEYS_MAX
STACK_MIN 一個執行緒的棧可用的最小位元組數 _SC_THREAD_STACK_MIN
THREADS_MAX 程序可以建立的最大執行緒數 _SC_THREAD_THREADS_MAX
#include <unistd.h>
#include <stdio.h>
#include <limits.h>
int main(void) { printf("DESTRUCTOR_ITERATIONS = %d\n", sysconf(_SC_THREAD_DESTRUCTOR_ITERATIONS)); printf("KEYS_MAX = %d\n", sysconf(_SC_THREAD_KEYS_MAX)); printf("STACK_MIN = %d\n", sysconf(_SC_THREAD_STACK_MIN)); printf("THREADS_MAX = %d\n", sysconf(_SC_THREAD_THREADS_MAX)); return
0; } result: DESTRUCTOR_ITERATIONS = 4 KEYS_MAX = 1024 STACK_MIN = 16384 THREADS_MAX = -1
  • 執行緒配置限制的例項
限制名稱 freebsd 8.0 Linux 3.2.0 maxOS X 10.6.8 Solaris 10
DESTRUCTOR_ITERATIONS 4 4 4 沒有確定的限制
KEYS_MAX 256 1024 512 沒有確定的限制
STACK_MIN 2048 16384 8192 8192
THREADS_MAX 沒有確定的限制 沒有確定的限制 沒有確定的限制 沒有確定的限制

執行緒屬性

  • pthread介面允許我們通過設定每個物件關聯的不同屬性來細調執行緒和同步物件的行為。
    • 如互斥量和互斥量屬性,執行緒與執行緒屬性
    • 有對應的初始化函式和銷燬函式以及獲取屬性值的函式
    • 每個屬性也有一個屬性設定函式
    • pthread_attr_init的實現是動態分配屬性物件,所以使用pthread_attr_destroy可以釋放該記憶體空間
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
  • posix.1執行緒屬性
    • 如果對執行緒終止狀態不感興趣的話,可以使用pthread_detach函式讓作業系統線上程退出時收回它所佔用的資源
名稱 描述 freebsd 8.0 Linux 3.2.0 maxOS X 10.6.8 Solaris 10
detachstate 執行緒的分離狀態屬性 支援 支援 支援 支援
guardsize 執行緒棧末尾的警戒緩衝區大小(位元組數) 支援 支援 支援 支援
stackaddr 執行緒棧的最低地址 支援 支援 支援 支援
stacksize 執行緒棧的最小長度(位元組數) 支援 支援 支援 支援
  • 設定執行緒分離狀態
    • 如果想讓執行緒一開始就處於分離狀態,就將該屬性設定為PTHREAD_CREATE_DETACHED,否則正常啟動就是PTHREAD_CREATE_JOINABLE
#include <pthread.h>
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);


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

int makethread(void *(*fn)(void *), void *arg);
void * f(void *arg);

pthread_t g_tid = 0;
int
main(void)
{
    int ret = makethread(f, NULL);
    if (ret) {
        printf("make thread error\n");
        exit(1);
    }

    sleep(3);
    pthread_join(g_tid, NULL);
    printf("join child_thread over\n");
    return 0;
}

int makethread(void *(*fn)(void *), void *arg)
{
    int err;
    pthread_t tid;
    pthread_attr_t attr;

    err = pthread_attr_init(&attr);
    if (0 != err)
        return (err);
    err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    if (0 == err)
        err = pthread_create(&tid, &attr, fn, arg);
    pthread_attr_destroy(&attr); // 這裡應該檢查執行緒屬性銷燬是否正常,如果不正常應該取消這個執行緒,否則會有少量的記憶體洩露

    g_tid = tid;
    return (err);
}

void *f(void *arg)
{
    printf("thread_comming!!!\n");
    while (1)
        sleep(1);

    return (NULL);
}

result:
[[email protected] 新建資料夾]# ./main
thread_comming!!!
join child_thread over
  • 獲取、設定執行緒棧屬性
    • 對於posix標準的作業系統來說,並不一定要支援執行緒棧屬性。但是尊徐single UNIX specification中xsi選項的E系統來說,需要支援執行緒棧屬性。
    • 下面的程式碼將直接設定執行緒棧的大小,如果執行緒棧太小,會直接段錯誤
//先來講說執行緒記憶體相關的東西,主要有下面幾條:
//程序中的所有的執行緒共享相同的地址空間。
//任何宣告為static/extern的變數或者堆變數可以被程序內所有的執行緒讀寫。
//一個執行緒真正擁有的唯一私有儲存是處理器暫存器。
//執行緒棧可以通過暴露棧地址的方式與其它執行緒進行共享。
// 有大資料量處理的應用中,有時我們有必要在棧空間分配一個大的記憶體塊或者要分配很多小的記憶體塊,但是執行緒的棧空間的最大值線上程建立的時候就已經定下來了,如果棧的大小超過個了個值,系統將訪問未授權的記憶體塊,毫無疑問,再來的肯定是一個段錯誤。可是沒辦法,你還是不得不分配這些記憶體,於是你開會為分配一個整數值而動用malloc這種超級耗時的操作。當然,在你的需求可以評估的情況下,你的需求還是可以通過修改執行緒的棧空間的大小來改變的。
//
//下面的我們用pthread_attr_getstacksize和pthread_attr_setstacksize的方法來檢視和設定執行緒的棧空間。

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <pthread.h>
#include <error.h>
#include <string.h>

//#ifndef _POSIX_THREAD_ATTR_STACKSIZE
//define _POSIX_THREAD_ATTR_STACKSIZE
//執行緒體,在棧中分配一個大小為8M的空間,並進行讀寫
void * thread_stack(void *arg)
{
    printf("The thread is here\n");
    //棧大小為8M,如果直接分配8M的棧空間,會出現段錯誤 ,因為棧中還有其它的
    //變數要放署
    char p[1024 * 1024 * 7];
    int i = 1024 * 1024 * 7;
    while (i--)
        p[i] = 3;

    printf("Get 7M Memory\n");

    //分配更多的記憶體(如果分配1024*1020*512的話就會出現段錯誤)
    char p2[1024 * 1020 + 256];
    memset(p2, 0, sizeof(char) * (1024 * 1020 + 256));

    printf("Get More Memory!!!\n");
    return NULL ;
}

int main(int argc, char ** argv)
{
    pthread_t thread_id;
    pthread_attr_t thread_attr;
    size_t stack_size;
    int err;

    err = pthread_attr_init(&thread_attr);
    if (err != 0)
        perror("Create attr");

    //設定分離狀態
    err = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
    if (err != 0)
        perror("Create attr");

    //通常出現的問題之一,下面的巨集沒有定義
    //#ifdef _POSIX_THREAD_ATTR_STACKSIZE
    //得到當前的執行緒棧大小
    err = pthread_attr_getstacksize(&thread_attr, &stack_size);
    if (err != 0)
        perror("Create attr");

    printf("Default stack size is %u; minimum is %u\n", stack_size,
            PTHREAD_STACK_MIN);

    //設定當前的執行緒的大小為16MB
    err = pthread_attr_setstacksize(&thread_attr, PTHREAD_STACK_MIN * 1024);
    if (err != 0)
        perror("Create attr");

    //得到當前的執行緒棧的大小
    err = pthread_attr_getstacksize(&thread_attr, &stack_size);
    if (err != 0)
        perror("Get stack size");

    printf("Default stack size is %u; minimum is %u\n", stack_size,
            PTHREAD_STACK_MIN);
    //#endif
    int i = 5;
    //分配5個具有上面的屬性的執行緒體的屬性的執行緒體
    while (i--) {
        err = pthread_create(&thread_id, &thread_attr, thread_stack, NULL );
        if (err != 0)
            perror("Create thread");
    }

    getchar();
    printf("Main exiting\n");

    pthread_exit(NULL );
    return 0;
}

result:
[[email protected] 新建資料夾]# ./main
Default stack size is 16785408; minimum is 16384
Default stack size is 16777216; minimum is 16384
The thread is here
The thread is here
The thread is here
The thread is here
The thread is here
Get 7M Memory
Get More Memory!!!
Get 7M Memory
Get More Memory!!!
Get 7M Memory
Get More Memory!!!
Get 7M Memory
Get More Memory!!!
Get 7M Memory
Get More Memory!!!

Main exiting
  • 執行緒屬性guardsize控制著執行緒棧末尾之後用以避免棧溢位的擴充套件記憶體的大小。預設值得看具體實現,但通常是系統頁的大小。如果設定為0,則不提供境界緩衝區。如果我們修改了執行緒屬性stackaddr,系統會認為是我們自己管理棧,進而使警戒緩衝區機制無效,等同於guardsize執行緒屬性設定為0
  • 如果guardsize被修改,作業系統會把它取為頁大小的證書倍。如果執行緒的棧指標溢位到了警戒區域,應用程式就可能通過訊號接收到出錯資訊
#include <pthread.h>

int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
int pthread_attr_getguardsize(pthread_attr_t *attr, size_t *guardsize);

Compile and link with -pthread.

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <pthread.h>
#include <error.h>
#include <string.h>

int main(int argc, char ** argv)
{
    pthread_t thread_id;
    pthread_attr_t thread_attr;
    size_t stack_size;
    int err;

    err = pthread_attr_init(&thread_attr);
    if (err != 0)
        perror("Create attr");

    size_t guard_size = 0;
    err = pthread_attr_getguardsize(&thread_attr, &guard_size);
    if (0 != err) {
        printf("pthread_attr_getguardsize error\n");
        exit(1);
    }

    printf("pthread_attr_getguardsize: %d\n", guard_size);

    guard_size = 7999;
    err = pthread_attr_setguardsize(&thread_attr, guard_size);
    if (0 != err) {
        printf("pthread_attr_setguardsize6 error\n");
        exit(1);
    }

    err = pthread_attr_getguardsize(&thread_attr, &guard_size);
    if (0 != err) {
        printf("pthread_attr_getguardsize error\n");
        exit(1);
    }

    printf("after pthread_attr_setguardsize: %d\n", guard_size);

    return 0;
}

result:
[[email protected] 新建資料夾]# ./main
pthread_attr_getguardsize: 4096
after pthread_attr_setguardsize: 7999

同步屬性

互斥量屬性
  • 互斥量有3個屬性指的注意:程序共享屬性、健壯屬性和型別屬性
    • PTHREAD_PROCESS_SHARED、PTHREAD_PROCESS_PRIVATE
  • 程序共享屬性測試程式碼:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>


#include <pthread.h>

#ifndef _POSIX_THREAD_PROCESS_SHARED
#error This system does not support process shared mutex
#endif

int shared_mem_id;
int *shared_mem_ptr;

pthread_mutexattr_t mutex_shared_attr;
pthread_mutex_t *mptr;

int
main(void)
{
    pid_t child_pid;
    int status, rtn;

    /* initialize shared memory segment */
    if ((shared_mem_id = shmget(IPC_PRIVATE, 1*sizeof(pthread_mutex_t), 0660)) < 0)
        perror("shmget"), exit(1) ;

    if ((shared_mem_ptr = (int *)shmat(shared_mem_id, (void *)0, 0)) == NULL)
        perror("shmat"), exit(1);

    mptr = (pthread_mutex_t *)shared_mem_ptr;

    if (( rtn = pthread_mutexattr_init(&mutex_shared_attr)) != 0)
        fprintf(stderr,"pthreas_mutexattr_init: %s",strerror(rtn)),exit(1);

    if (( rtn = pthread_mutexattr_setpshared(&mutex_shared_attr,PTHREAD_PROCESS_SHARED)) != 0)
        fprintf(stderr,"pthread_mutexattr_setpshared %s",strerror(rtn)),exit(1);

    if (( rtn = pthread_mutex_init(mptr, &mutex_shared_attr)) != 0)
        fprintf(stderr,"pthread_mutex_init %s",strerror(rtn)), exit(1);


    if ((child_pid = fork()) == 0) {
        /* first child */
        if ((rtn = pthread_mutex_lock(mptr)) != 0)
            fprintf(stderr,"child:pthread_mutex_lock %s",strerror(rtn)),exit(1);
        sleep(1);

        if ((rtn = pthread_mutex_unlock(mptr)) != 0)
            fprintf(stderr,"child:pthread_unmutex_lock %s",strerror(rtn)),exit(1);
        printf("child exit\n");
        exit(0);
    } else {
        /* parent */
        sleep(1);
        if ((rtn = pthread_mutex_lock(mptr)) != 0)
            fprintf(stderr,"parent:pthread_mutex_lock %d",strerror(rtn)),exit(1);
        if ((rtn = pthread_mutex_unlock(mptr)) != 0)
            fprintf(stderr,"child:pthread_unmutex_lock %d",strerror(rtn)),exit(1);
        wait(&status);
        printf("recycle child\n");
    }
    return 0;
}

result:
[[email protected] 新建資料夾]# ./main
child exit
recycle child
  • 互斥量健壯屬性(與多個程序間共享的互斥量有關):程序終止時,互斥量處於鎖定狀態,恢復起來很困難。
    • PTHREAD_MUTEX_STALLED:當健壯屬性取值為這個值的時,意味著持有互斥量的程序終止時不採取特別的動作,這樣使用互斥量後的行為是未定義的
    • PTHREAD_MUTEX_ROBUST:這個值會導致呼叫pthread_mutex_lock獲取鎖的程序a的執行緒當鎖被另外一個程序b的執行緒佔有,並且程序b執行緒終止時並沒有對該鎖進行解鎖,此時a程序的執行緒會阻塞,從pthread_mutex_lock返回的值為EOWNERRERAD而不是0,程序a的執行緒通過這個特殊值獲知。如果程序a的執行緒想繼續獲取鎖,得使用pthread_mutex_consistent
// example1:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <errno.h>

#include <pthread.h>

#ifndef _POSIX_THREAD_PROCESS_SHARED
#error This system does not support process shared mutex
#endif

int shared_mem_id;
int *shared_mem_ptr;

pthread_mutexattr_t mutex_shared_attr;
pthread_mutex_t *mptr;

int
main(void)
{
    pid_t child_pid;
    int status, rtn;

    /* initialize shared memory segment */
    if ((shared_mem_id = shmget(IPC_PRIVATE, 1*sizeof(pthread_mutex_t), 0660)) < 0)
        perror("shmget"), exit(1) ;

    if ((shared_mem_ptr = (int *)shmat(shared_mem_id, (void *)0
            
           

相關推薦

12 執行控制

請移步到這: 12.2 執行緒限制 12.3 執行緒屬性 執行緒具有一系列屬性,這些屬性可以線上程建立的時候指定。 只需要建立並填充一個 pthrea_attr t型別的執行緒屬性物件ATTR, 並將其作為第二個引數傳遞給pthread create就可

執行執行者引言

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

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() { // 執行 //

讀書筆記--《程式設計師的自我修養》4:靜態連結1

本章以 如何將a.c檔案與b.c檔案連結成一個可執行檔案 來探討如何進行靜態連結 其中a.c和b.c檔案如下: a.c檔案 extern int shared; int main() { int a = 100; swap(&a,&shared);

【計算機網路】 資料鏈路層1

一.資料鏈路層服務 1. 概述 (1)術語   ·主機和路由器:結點   ·連線相鄰結點的通訊通道:鏈路(有線、無線、區域網)   ·鏈路層資料分組:幀 (2)資料鏈路層主要任務:通過一條鏈路從一個結點向另一個物理鏈路直接相連的相鄰結點傳送資料報 2. 鏈路層服務 (1)組幀   ·封裝資料

java多執行知識1

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

7 網路層協議1_網路層首部

1. 網路層首部 1.1 網路層協議 (1)TCP/IP協議棧網路層的4個協議:IP協議、ICMP協議、IGMP協議和ARP協議。 (2)IP協議:動態路上協議的統稱,包括RIP和OSPF協議。 (3)TCP/IP協議分成四層:應用層定義了客戶端和伺服器通訊規範,傳輸層實現可靠

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-執行安全和鎖Synchronized概念

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

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

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

30 混編模式1

30.1 命令鏈模式(命令模式+責任鏈模式) 30.1.1 UNIX下的命令規則(如ls) (1)命令名為小寫字母 (2)命令名、選項、運算元之間以空格分隔,空格數量不受限制 (3)選項之間可以組合使用,也可以單獨拆分使用 (4)選項以“-”開頭 30.1.2 l

java執行複習1

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

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

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

第一-執行管理引言

宣告:本文是《 Java 7 Concurrency Cookbook 》的第一章, 作者: Javier Fernández González 譯者:鄭玉婷 校對:歐振聰 1 執行緒管理 章節提要: 介紹 在計算機世界,當人們談到併發時,它的意思是一系列的任務在計算機中同時執行。如果計算

java 執行1

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

《機器學習實戰》:Logistic迴歸1基本概念和簡單例項

最近感覺時間越來越寶貴,越來越不夠用。不過還是抽空看了點書,然後整理到部落格來。 加快點節奏,廢話少說。 Keep calm & carry on. ----------------------------------------------------------

執行學習1

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

執行控制

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