C++11多线程基础

 

1. join

#include <iostream>
#include <thread>

using namespace std;

void fun()   //子线程
{
    for (int i = 0; i < 100; i++)
        cout << "*";
}

void main()
{
    thread t(fun);   //创建线程,线程从fun()函数开始执行
    t.join();   //阻塞主线程,让主线程等待子线程执行完毕

    for (int i = 0; i < 100; i++)   //主线程
        cout << "$";
}

输出:****************************************************************************************************$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

 

#include <iostream>
#include <thread>

using namespace std;

void fun()   //子线程
{
    for (int i = 0; i < 100; i++)
        cout << "*";
}

void main()
{
    thread t(fun);   //创建线程,线程从fun()函数开始执行

    for (int i = 0; i < 100; i++)   //主线程
        cout << "$";

    t.join();   //阻塞主线程,让主线程等待子线程执行完毕
}

输出:

*****************************************$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$*******************$$$$$$$$$*************************************$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$***

 

#include <iostream>
#include <thread>

using namespace std;

void fun()   //子线程
{
    for (int i = 0; i < 100; i++)
        cout << "*";
}

void main()
{
    thread t(fun);   //创建线程,线程从fun()函数开始执行

    for (int i = 0; i < 100; i++)   //主线程
        cout << "$";
}

输出:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16$$ 17$$ 18 19 20 21 22 23 24 25 26 $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$27

 

2. detach

#include <iostream>
#include <thread>

using namespace std;

void fun()   //子线程
{
    for (int i = 0; i < 100; i++)
        cout << i << " ";
}

void main()
{
    thread t(fun);   //创建线程,线程从fun()函数开始执行
    t.detach();   //主线程不等待子线程执行完毕就可以先行退出,子线程驻留在后台运行

    for (int i = 0; i < 100; i++)   //主线程
        cout << "$";
}

输出:

0 1 2 3 4 $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$5

 

3. joinable

#include <iostream>
#include <thread>

using namespace std;

void fun()   //子线程
{
    for (int i = 0; i < 100; i++)
        cout << i << " ";
}

void main()
{
    thread t(fun);   //创建线程,线程从fun()函数开始执行

    if (t.joinable())   //判断是否可以成功使用join()或者detach(),调用join后不能再调用join和detach,调用detach后也不能再调用join和detach。因为重复调用会导致异常
    {
        t.join();
        cout << "joinable() == true" << endl;
    }

    for (int i = 0; i < 100; i++)   //主线程
        cout << "$";
}

输出:****************************************************************************************************$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

 

4. 可调用对象

#include <iostream>
#include <thread>

using namespace std;class A
{
public:
    void operator()()   //不能带参数
    {
        for (int i = 0; i < 100; i++)   //子线程
            cout << i << " ";
    }
};

void main()
{
    A a;   //a:可调用对象
    thread t(a);   //将对象a复制到子线程中,执行完主线程后,对象a会被销毁,但是复制到子线程中的对象依旧存在。只要这个A类对象没有主线程中的引用或指针,就不会出现问题。
    t.join();   //阻塞主线程,让主线程等待子线程执行完毕

    for (int i = 0; i < 100; i++)   //主线程
        cout << "$";
}

输出:****************************************************************************************************$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

 

5.lambda表达式

#include <iostream>
#include <thread>

using namespace std;void main()
{
    auto lamthread = [] {

        for (int i = 0; i < 100; i++)
            cout << i << " ";
    };

    thread t(lamthread);
    t.join();
}

输出:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99

 

6. 陷阱

#include <iostream>
#include <thread>

using namespace std;

void fun(const int& i, char* buf)   //子线程
{
    cout << i << endl;
    cout << buf << endl;
}

void main()
{
    int num = 9;
    char buf[] = "abc";

    thread t(fun, num, buf);
    t.join();

    cout << "i love you" << endl;
}

输出:

9
abc
i love you

 

#include <iostream>
#include <thread>

using namespace std;

void fun(const int& i, char* buf)   //子线程
{
    cout << i << endl;   //i并不是num的引用,实际是值传递。即使主线程使用detach,子线程中的i也是安全的。最好不使用引用。
    cout << buf << endl;   //指针在主线程使用detach时,绝对会有问题。因为主线程中的buf已经被释放,所以子线程中的buf就变成了野指针。
}

void main()
{
    int num = 9;
    char buf[] = "abc";

    thread t(fun, num, buf);   //有问题
    t.detach();
}
#include <iostream>
#include <thread>

using namespace std;

void fun(const int& i, string& buf)   //子线程
{
    cout << i << endl;
    cout << buf.c_str() << endl;
}

void main()
{
    int num = 9;
    char buf[] = "abc";

    thread t(fun, num, string(buf));   //没问题。用临时构造的string类对象作为参数传递给线程,一定能在主线程执行完毕前把线程函数的第二个参数构造出来,从而确保主线程即便detach了子线程也能安全运行。
    t.detach();
}
#include <iostream>
#include <thread>

using namespace std;

class A
{
public:
    //类型转换构造函数,可以把一个int转换成一个类A对象
    A(int i) :m_i(i) { cout << "调用构造函数" << this << endl; }
    A(const A& a) :m_i(a.m_i) { cout << "调用拷贝构造函数}" << this << endl; }
    A() { cout << "调用析构函数" << this << endl; }
private:
    int m_i;
};

void fun(const int& i, const A& a)   //子线程
{
    cout << i << endl;
    cout << &a << endl;   //输出对象地址
}

void main()
{
    int num = 9;int sum = 0;

    thread t(fun, num, sum);   //有时候都还没调用构造函数主线程就退出了,则会有问题。需要改成创建临时对象thread t(fun, num, A(sum));
    t.detach();
}
#include <iostream>
#include <thread>

using namespace std;

class A
{
public:
    //类型转换构造函数,可以把一个int转换成一个类A对象
    A(int i) :m_i(i) { cout << "调用构造函数" << this << endl; }
    A(const A& a) :m_i(a.m_i) { cout << "调用拷贝构造函数}" << this << endl; }
    A() { cout << "调用析构函数" << this << endl; }
private:
    int m_i;
};

void fun(const int& i, const A& a)   //子线程
{
    cout << i << endl;
    cout << &a << endl;   //输出对象地址
}

void main()
{
    int num = 9;int sum = 0;

    thread t(fun, num, A(sum));   //绝对没问题。绝对在先调用构造函数后再退出主线程
    t.detach();
}

输出:

调用构造函数00ADF884
调用拷贝构造函数}00E54B58
9

 

 

8. 线程id

验证:

#include <iostream>
#include <thread>

using namespace std;

class A
{
public:
    //类型转换构造函数,可以把一个int转换成一个类A对象
    A(int i) :m_i(i) { cout << "调用构造函数" << this << " threadid:" << std::this_thread::get_id() << endl; }
    A(const A& a) :m_i(a.m_i) { cout << "调用拷贝构造函数}" << this << " threadid:" << std::this_thread::get_id() << endl; }
    A() { cout << "调用析构函数" << this << " threadid:" << std::this_thread::get_id() << endl; }
private:
    int m_i;
};

void fun(const A& a)   //子线程
{
    cout << "a threadid:" << std::this_thread::get_id() << endl;
    cout << &a << endl;   //输出对象地址
}

void main()
{
    cout << "主线程id:" << std::this_thread::get_id() << endl;

    int num = 9;int sum = 0;

    thread t(fun, sum);   //在子线程中构造的A类对象。当调用detach时显然会出问题,因为sum已释放,则子线程中的sum就是不可预知的值。
    t.join();
}

输出:

主线程id:5300
调用构造函数00CCF7E4 threadid:6380
a threadid:6380
00CCF7E4

 

#include <iostream>
#include <thread>

using namespace std;

class A
{
public:
    //类型转换构造函数,可以把一个int转换成一个类A对象
    A(int i) :m_i(i) { cout << "调用构造函数" << this << " threadid:" << std::this_thread::get_id() << endl; }
    A(const A& a) :m_i(a.m_i) { cout << "调用拷贝构造函数}" << this << " threadid:" << std::this_thread::get_id() << endl; }
    A() { cout << "调用析构函数" << this << " threadid:" << std::this_thread::get_id() << endl; }
private:
    int m_i;
};

void fun(const A& a)   //子线程。  用引用传递,否则得多调用一次拷贝构造函数
{
    cout << "a threadid:" << std::this_thread::get_id() << endl;
    cout << &a << endl;   //输出对象地址
}

void main()
{
    cout << "主线程id:" << std::this_thread::get_id() << endl;

    int num = 9;
    int sum = 0;

    thread t(fun, A(sum));   //主线程中构造的A类对象。当调用detach时也不会有问题
    t.join();
}

输出:

主线程id:18328
调用构造函数003CF874 threadid:18328
调用拷贝构造函数}0043AD88 threadid:18328
a threadid:14056
0043AD88

 

 

8.  

 

posted @ 2021-07-12 20:18  远方是什么样子  阅读(49)  评论(0编辑  收藏  举报