使用C11新增的多執行緒支援庫-threads.h進行多執行緒程式設計

2019年12月6日更新

首先要感謝評論區的熱心的同學們的提醒,經本人親自驗證:

VS 2019中移除了對threads.h的支援(評論區有同學提到單獨安裝v140工具集可以實現支援,但是測試發現沒有效果),而GCC方面則在最新版中加入了對該標頭檔案的支援。

以下為原文(程式程式碼部分更新了Linux版Dome)。


導語

threads.h是C11標準新增的多執行緒支援庫,在此之前C語言實現多執行緒,除了使用系統API外用的最多的就是pthread.h了,threads.h在語法上和pthread.h非常相似。
當然,對於新出的C語言標準,各大編譯器廠商並不會馬上就支援。就比如說,Linux下主流的C語言編譯器————GCC,直到GCC7.2版本都沒能支援該庫(PS:看到老外網站上說要安裝最新版glibc才能獲得對該庫的支援,然而親測無卵用)。相反,VS在這方面做的就很不錯,VS2017已經可以完美支援該庫了,本文也將基於VS2017社羣版對該庫的使用方法做介紹。

注:本文僅對多執行緒程式設計的概念及threads.h庫檔案的使用方法做簡單介紹,並不會詳盡介紹該庫下的所有函式,如果你需要一個函式功能的參考手冊可以參考此篇文章:C11新增多執行緒支援庫-threads.h參考手冊

以一個小程式為例子

本程式中使用到的庫函式及宏:

  • thrd_t //此宏定義用於存放執行緒識別符號的資料型別
  • thrd_create //此函式用於建立執行緒
  • thrd_detach //此函式用於通知作業系統,當執行緒結束時由作業系統負責釋放資源
  • thrd_exit //此函式用於結束當前執行緒

程式功能:

主執行緒每2秒列印一次“I love ibadboy.net~~~”,共列印10次。子執行緒每1秒列印一次“He love ibadboy.net!!!”,共列印10次。我們知道,在只有一個主執行緒的C程式中該功能是無法實現的,因為後一段程式程式碼必須等待前一段程式碼執行完畢才可執行。但,在多執行緒程式設計中,各個執行緒可以一起執行(這裡涉及到的同步、非同步等等的高階技術就不討論了)。舉個例子:在遊戲開發中,如果程式需要實時監控使用者鍵盤的輸入,就不能把這段程式碼放到主執行緒中,因為這樣的話該段程式碼就會被程式的其他部分阻塞掉而無法做到真正的“實時”,這時就可以利用多執行緒技術來化解尷尬啦!話不多說,直接上程式碼!

程式程式碼Linux版本

#include <stdio.h>
#include <unistd.h>	//包含sleep等函式
#include <stdbool.h>
#include <threads.h>	//包含多執行緒支援庫標頭檔案
#include <stdlib.h>	//包含exit等函式

int thr_fun(void *);

int main(void) {
    thrd_t thr;
    int ret; //儲存thrd_create函式的返回值用於判斷執行緒是否建立成功:0為成功,1為失敗。
    ret = thrd_create(&thr, thr_fun, NULL); //將thr_fun函式放在一個新的執行緒中執行
    if (ret != thrd_success) {
        printf("error!!!\n");
        getchar();
        exit(-1);
    }
    ret = thrd_detach(thr); //通知作業系統,該執行緒結束時由作業系統負責釋放資源。
    if (ret != thrd_success) {
        printf("error!!!\n");
        getchar();
        exit(-1);
    }
    for (int i = 0; i < 10; i++) {
        sleep(2);
        printf("I love ibadboy.net~~~\n");
    }
    getchar();
    return 0;
}

int thr_fun(void *argv) {
    int i = 0;
    while (true) {
        i++;
        sleep(1);
        printf("He love ibadboy.net!!!\n");
        if (i == 10) {
            thrd_exit(0);
        }
    }
}

編譯命令:

gcc a.c -std=c11 -lpthread

程式程式碼Windows版本(經測試在VS 2019中已無法編譯透過):

#include<stdio.h>
#include<stdbool.h>
#include<thr/threads.h>        //包含多執行緒支援庫標頭檔案
#include<Windows.h>
void thr_fun(void);
int main(void) {
    thrd_t thr;
    int ret;    //儲存thrd_create函式的返回值用於判斷執行緒是否建立成功:0為成功,1為失敗。
    ret = thrd_create(&thr, thr_fun, NULL);        //將thr_fun函式放在一個新的執行緒中執行
    if (ret != thrd_success) {
        printf("error!!!\n");
        getchar();
        exit(-1);
    }
    ret = thrd_detach(thr);    //通知作業系統,該執行緒結束時由作業系統負責釋放資源。
    if (ret != thrd_success) {
        printf("error!!!\n");
        getchar();
        exit(-1);
    }
    for (int i = 0; i < 10; i++) {
        Sleep(2000);
        printf("I love ibadboy.net~~~\n");
    }
    getchar();
    return 0;
}
void thr_fun(void) {
    int i = 0;
    while (true) {
        i++;
        Sleep(1000);
        printf("He love ibadboy.net!!!\n");
        if (i == 10) {
            thrd_exit(0);
        }
    }
}

程式輸出:

C語言多執行緒演示小程式的程式碼輸出

程式中用到的庫函式介紹:

thrd_create函式用於建立新執行緒,如果建立成功,該函式會返回thrd_success,否則返回thrd_error

函式原型:

int thrd_create(thrd_t *thr, thrd_start_t func, void *arg);

引數說明:

  • thr:指向放置新執行緒識別符號的記憶體位置的指標。
  • func:要放在子執行緒中執行的函式。
  • arg:傳遞給執行的函式的引數,無引數填NULL。

thrd_detach函式用於通知作業系統,當執行緒結束後由作業系統負責釋放資源,如果成功,則返回thrd_success,否則為thrd_error,如不呼叫該函式,則執行緒所使用的資源將在程式全部執行完後才會釋放。

函式原型:

int thrd_detach( thrd_t thr );

引數說明:

  • thr:要作用的執行緒的識別符號

thrd_exit函式用於結束當前程序,值得一提的是:使用該函式可以在不影響子程序的情況下結束主程序,而使用exit函式的話結束主程序將會連帶結束整個程式。

函式原型:

_Noreturn void thrd_exit( int res );

引數說明:

  • res:要返回的值

結語

看完此篇文章相信你已經對使用threads.h庫進行C語言的多執行緒開發有了初步瞭解,如果還有什麼問題的話歡迎在評論區留言哦~

14 thoughts on “使用C11新增的多執行緒支援庫-threads.h進行多執行緒程式設計”

  1. 嗯,考慮到博主用到了Windows.h,並且用了一些API,造成了在gcc下編譯不過,程式碼修改如下:

    #include
    #include //包含sleep等函式
    #include
    #include //包含多執行緒支援庫標頭檔案
    #include //包含exit等函式

    int thr_fun(void *);

    int main(void) {
    thrd_t thr;
    int ret; //儲存thrd_create函式的返回值用於判斷執行緒是否建立成功:0為成功,1為失敗。
    ret = thrd_create(&thr, thr_fun, NULL); //將thr_fun函式放在一個新的執行緒中執行
    if (ret != thrd_success) {
    printf(“error!!!\n”);
    getchar();
    exit(-1);
    }
    ret = thrd_detach(thr); //通知作業系統,該執行緒結束時由作業系統負責釋放資源。
    if (ret != thrd_success) {
    printf(“error!!!\n”);
    getchar();
    exit(-1);
    }
    for (int i = 0; i < 10; i++) {
    sleep(10);
    printf("I love ibadboy.net~~~\n");
    }
    getchar();
    return 0;
    }
    int thr_fun(void *argv) {
    int i = 0;
    while (true) {
    i++;
    sleep(5);
    printf("He love ibadboy.net!!!\n");
    if (i == 10) {
    thrd_exit(0);
    }
    }
    }

  2. 現在是2019年,情況有些變化,gcc+glibc在glibc的2.28版加入了threads.h,現在的gcc可以直接使用這個標頭檔案,另外,musl libc庫早在2014年就加入了這個標頭檔案。
    另外從我的系統搜尋得知dietlibc也支援,加入時間未知。

    1. 在這個浮躁的時代還能遇到這麼走心的評論,難得,難得。我會盡快驗證你的程式碼並更新到文章上,同時註明作者的。

  3. 剛剛找到了,必須要安裝單元件v140工具集才行。估計是VS2015的MSVC中才有這個threads.h標頭。而到了VS2017及其之後都被移除了。之前提的那個宏定義__STDC_NO_THREADS__我看錯了,它是定義在Linux開發標頭裡面的,不知道MSVC中是否也同樣定義了不支援的宏。

    1. 不好意思!遲來的回覆,感謝你的提醒!我會盡快驗證並更新文章的!更新的部分會著名作者的!

  4. 我VS2017社羣版15.9.11裡面全部的元件都安裝了都沒有這個標頭,而且thr下只有以下幾個標頭:xthrcommon.h xthread xthreads.h xtime xtimec.h。VS2019同樣也沒有!
    看了c11標準說明:若編譯器定義宏常量 __STDC_NO_THREADS__(C11) ,則不提供標頭檔案 和所有列於此的名稱。VS2017裡面就有定義這個宏:
    /* We do not support C11 . */
    #define __STDC_NO_THREADS__ 1
    按照微軟官方的回覆來看,好像他壓根就不支援C11的執行緒庫:https://developercommunity.visualstudio.com/content/problem/463485/couldnt-find-file-thrthreadsh.html

    1. 我釋出文章的時候確實是支援的,但是我今天使用VS 2019測試後發現目前版本已經不再支援。根據目前掌握的資訊來看:微軟的VS主要目標是支援C++,對C的支援是次要的

    1. 兄弟問題解決了嗎?我現在在VS 2019中也使用不了這個頭。如果解決了可以給大家分享一下

  5. 你好,請問下 thr/threads.h 這個庫是需要單獨裝什麼東西嗎,我的vs2017提示找不到該檔案

  6. 發現你的程式碼有點問題,void thr_fun(void);我用你的原始碼vs2017提示錯誤嚴重性 程式碼 說明 專案 檔案 行 禁止顯示狀態
    錯誤 C2664 “int _Thrd_create(_Thrd_t *,_Thrd_start_t,void *)”: 無法將引數 2 從“int (__cdecl *)(void)”轉換為“_Thrd_start_t” 多執行緒 e:\code\c\多執行緒\多執行緒\main.cpp 23
    我的vs2017版本是10.0.16299.0。thr_fun函式需要修改一下int thr_fun(void *arg)就編譯透過了。

Leave a Reply to 絕世壞蛋 Cancel reply

Your email address will not be published. Required fields are marked *

Captcha Code