C++std::thread

1.std::thread的使用:

        std::thread是C++11提出的,因此使用std::thread需要c++11或c++11以上标准。在linux使用std::thread时需要在编译时链接-lpthread。

2.使用thread的例子:

        下列代码开启了一个简单的thread

#include <thread>
#include <unistd.h>
#include <iostream>

void func(int a)
{
    for (int i = 0; i < 9; i++) {
        usleep(1000);//等待1000微秒,即1毫秒。
        a+=1;
        std::cout << a<<' ';
    }
}

int main()
{
    int a = 0;
    std::thread t1(func,a);//函数名和参数,没有参数的函数则只需写函数名
    func(a);
    t1.join();//线程必须伴随join或者detach,具体在后文介绍
    return 0;
}

        运行结果如下:

        其中使用usleep是为了给程序添加延时,否则func速度非常快,会使得还没有在主线程执行func,创建的线程t1已经执行完毕。

3.thread传递引用:

        当函数参数传递为引用传递时,要加std::ref()修饰,如下:

void func(int& a)
{
    for (int i = 0; i < 9; i++) {
        a+=1;
    }
}

int main()
{
    int a = 0;
    std::thread t1(func,std::ref(a));//不写std::ref(a)而直接写a会报错
    t1.join();
    return 0;
}

 4.join()和detach():

        std::thread创建后需要在同一个作用域内调用join() 或者 detach(), 否则退出作用域后,程序会异常退出。如使用join主线程会阻塞在调用join的地方,直到线程完成。调用detach主线程可以正常退出,子线程被挪到后台运行,这些子线程会被C++运行时库接管,当这些子线程运行完毕后,由运行时库清理线程相关的资源, 即就是守护线程。一个线程只能从join和detach选择一种,不可以既是join又是detach。

        当使用new创建thread时,在delete之前也必须指定join或者detach,否则无法delete。

        使用detach时由于主线程不会等待子线程,因此子线程里面如果有指向主线程资源的指针或者引用很可能会因为主线程资源已释放导致错误。例子如下:

#include <thread>
#include <unistd.h>
#include <iostream>

void func1(int& a)
{
    for (int i = 0; i < 9; i++) {
        usleep(1000);//等待1000微秒,即1毫秒。
        a+=1;
        std::cout << a<<' ';
    }
}

void func2(int* a)
{
    for (int i = 0; i < 9; i++) {
        usleep(1000);//等待1000微秒,即1毫秒。
        *a += 1;
        std::cout << *a << ' ';
    }
}

int main()
{
    int a = 0;
    int* b = &a;
    std::thread t1(func1,std::ref(a));
    std::thread t2(func2, b);
    t1.detach();
    t2.detach();
    return 0;
}

        该程序将无法正确运行,理论上应该输出20个数,然而实际上只会输出一两个或不输出,因为主线程把a释放了导致子线程的引用和指针无法正确访问a

posted @ 2022-05-07 14:40  shldy1999  阅读(143)  评论(0)    收藏  举报