使用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

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