参考资料

线程的创建

线程的创建有多种方式

std::thread t1(可调用对象);

由于实现(内部的实现这里不在探讨),std::thread()创建一个新的线程可以接受任意的可调用对象类型(带参数或者不带参数),包括lambda表达式(带变量捕获或者不带),函数,函数对象,以及函数指针。

下面简单的探讨一下。

1.通过一个不带参数的函数创建线程。

#include <iostream>
#include <thread> // 多线程头文件 void Hello() {
std::cout << "Hello, World!" << std::endl;
} int main() {
// 创建一个线程对象,注意函数 Hello 将立即运行。
std::thread t(&Hello); // 等待线程结束。
// 否则线程还没执行(完),主程序就已经结束了。
t.join(); return 0;
}

cppreference 关于立即运行有提到

在启动了一个线程(创建了一个thread对象)之后,当这个线程结束的时候(std::terminate()),我们如何去回收线程所使用的资源呢?

thread库给我们两种选择:

  • 1.加入式(join())
  • 2.分离式(detach())

值得一提的是,你必须在thread对象销毁之前做出选择 这是因为线程可能在你加入或分离线程之前,就已经结束了,之后如果再去分离它,线程可能会在thread对象销毁之后继续运行下去。

2.通过一个带参数的函数创建线程。

#include <iostream>
#include <thread> void Hello(const char* what) {
// 睡眠一秒以模拟数据处理。
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Hello, " << what << "!" << std::endl;
} int main() {
std::thread t(&Hello, "World"); // 等价于使用 bind:
// std::thread t(std::bind(&Hello, "World")); t.join(); return 0;
}

3.通过一个函数对象——即仿函数(functor)——创建线程。

class Hello {
public:
void operator()(const char* what) {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Hello, " << what << "!" << std::endl;
}
}; int main() {
Hello hello; // 方式一:拷贝函数对象。
std::thread t1(hello, "World");
t1.join(); // 方式二:不拷贝函数对象,通过 boost::ref 传入引用。
// 用户必须保证被线程引用的函数对象,拥有超出线程的生命期。
// 比如这里通过 join 线程保证了这一点。
std::thread t2(std::ref(hello), "World");
t2. return 0;
}

4.通过一个成员函数创建线程。

// 通过成员函数来创建线程. 注意和普通函数的区别
#include <thread>
#include <iostream> class Hello {
public:
void ThreadFuntion() {
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "ThreadFuntion1 " << std::this_thread::get_id() << std::endl;
}
}; int main() {
Hello hello; // 需要一个对象
std::thread t1(&Hello::ThreadFuntion, &hello);
t1.join(); return 0;
}

5.通过一个成员函数创建线程(在构造函数中操作)。

与前例不同之处在于,需要以 bind 绑定 this 指针作为第一个参数。

#include <iostream>
#include <thread> class Hello {
public:
Hello() {
std::thread t(std::bind(&Hello::Entry, this, "World"));
t.join();
} private:
// 线程函数
void Entry(const char* what) {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Hello, " << what << "!" << std::endl;
}
}; int main() {
Hello hello;
return 0;
}

6.使用lambda

#include <iostream>
#include <thread> //
int main() {
auto threadFunction = []() {
std::cout << "Lambda thread id " << std::this_thread::get_id() <<std::endl; // 打印线程id
std::cout << "使用lambda表达式作为可调用对象" << std::endl;
}; std::cout << "Main thread id " << std::this_thread::get_id() <<std::endl;
std::thread t1(threadFunction);
t1.join();
return 0;
}

join Vs detach

join

join()字面意思是连接一个线程,意味着主动地等待线程的终止。

join()是这样工作的,在调用进程中join(),当新的线程终止时,join()会清理相关的资源(any storage associated with the thread),然后返回,调用线程再继续向下执行。 正是由于join()清理了线程的相关资源,因而我们之前的thread对象与已销毁的线程就没有关系了,这意味着一个线程的对象每次你只能使用一次join(),当你调用的join()之后joinable()就将返回false了。

关于joinable()

判断是否可以成功使用join() 或者detach(), 返回值为bool .

#include <iostream>
#include <thread> void foo()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
} int main()
{
std::thread t(foo);
std::cout << "before joining,joinable=" << std::boolalpha << t.joinable() << std::endl;
t.join();
std::cout << "after joining, joinable=" << std::boolalpha << t.joinable() << '\n';
} // output
// [thread]main
// before joining,joinable=true
// after joining, joinable=false

detach

分离式,对应的函数是detach()。

detach这个词的意思是分离的意思,对一个thread对象使用detach()意味着从调用线程分理出这个新的线程,我们称分离的线程叫做守护线程(daemon threads)。之后也就不能再与这个线程交互。

分离的线程会在后台运行,其所有权(ownership)和控制权将会交给c++运行库。同时,C++运行库保证,当线程退出时,其相关资源的能够正确的回收。

分离的线程,它运行结束后,不再需要通知调用它的线程

线程的标识

线程id。

类 thread::id 是轻量的可频繁复制类,它作为 std::thread 对象的唯一标识符工作。

  • std::this_thread::get_id()这个函数获取线程的标识符 (在线程的函数中)
  • 线程对象也有一个function get_id() std::thread::id get_id() const noexcept;
// source: cppreference
#include <iostream>
#include <thread>
#include <chrono> void foo()
{
// 看这里
std::cout << std::this_thread::get_id() <<std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
} int main()
{
// 看这里
std::thread t1(foo);
std::thread::id t1_id = t1.get_id(); std::thread t2(foo);
std::thread::id t2_id = t2.get_id(); std::cout << "t1's id: " << t1_id << '\n';
std::cout << "t2's id: " << t2_id << '\n'; t1.join();
t2.join();
}

C++11多线程编程--线程创建的更多相关文章

  1. Linux多线程编程——线程的创建与退出

    POSIX线程标准:该标准定义了创建和操纵线程的一整套API.在类Unix操作系统(Unix.Linux.Mac OS X等)中,都使用Pthreads作为操作系统的线程.Windows操作系统也有其 ...

  2. C++11 多线程编程 使用lambda创建std::thread (生产/消费者模式)

    要写个tcp server / client的博客,想着先写个c++11多线程程序.方便后面写博客使用. 目前c++11中写多线程已经很方便了,不用再像之前的pthread_create,c++11中 ...

  3. java多线程编程(二创建线程)

    1.概念           因为java是完全面向对象的,所以在java中,我们说的线程,就是Thread类的一个实例对象.所以,一个线程就是一个对象,它有自己字段和方法. 2.创建线程 创建线程有 ...

  4. C++11多线程编程

    1. 多线程编程 在进行桌面应用程序开发的时候, 假设应用程序在某些情况下需要处理比较复杂的逻辑, 如果只有一个线程去处理,就会导致窗口卡顿,无法处理用户的相关操作.这种情况下就需要使用多线程,其中一 ...

  5. Java基础加强之多线程篇(线程创建与终止、互斥、通信、本地变量)

    线程创建与终止 线程创建 Thread类与Runnable接口的关系 public interface Runnable { public abstract void run(); } public ...

  6. Java基础之多线程篇(线程创建与终止、互斥、通信、本地变量)

    线程创建与终止 线程创建 Thread类与Runnable接口的关系 public interface Runnable { public abstract void run(); } public ...

  7. Python多线程之线程创建和终止

    python主要是通过thread和threading这两个模块来实现多线程支持. python的thread模块是比較底层的模块,python的threading模块是对thread做了一些封装,能 ...

  8. Linux C多线程编程-线程互斥

    Linux下的多线程编程需要注意的是程序需要包含头文件pthread.h,在生成可执行文件的时候需要链接库libpthread.a或者libpthread.so. 线程创建函数: pthread_cr ...

  9. win32多线程: 线程创建与结束等待

    #include<Windows.h> #include<iostream> using namespace std; /*1.在启动一个线程之前,必须为线程编写一个全局的线程 ...

随机推荐

  1. Mac上使用brew另装ruby和gem的新玩法

    [本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究.若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!] 众所周知,Mac ...

  2. Day10-微信小程序实战-交友小程序-自定义callPhone 和copyText组件

    ---为了方便用户可以拨打电话和复制微信号(下面就要实现这样的两个功能) 注意:在小程序中是没办法直接的添加用户的微信的,所以就只能是复制微信号 (这种东西的话可以直接去做,也可以做成组件,做出组件的 ...

  3. Vue数据更新页面没有更新问题总结

    Vue数据更新页面没有更新问题总结 1. Vue无法检测实例别创建时不存在于data中的property 原因: 由于Vue会在初始化实例时对property执行getter/setter转化,所以p ...

  4. Python 简明教程 --- 19,Python 类与对象

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 那些能用计算机迅速解决的问题,就别用手做了. -- Tom Duff 目录 上一节 我们介绍了Pyt ...

  5. springboot的jar为何能独立运行

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  6. Windows Defender might be impacting your build performance

    由于换了SSD, 昨天安装了最新的 Idea 2019.2+ , 然后发现每次导入项目都有如下提示: 处理方法就是在Windows安全中心排除目录 处理方式参考: 官方 Known issues An ...

  7. 洛谷P3694 邦邦的大合唱站队【状压dp】

    状压dp 应用思想,找准状态,多考虑状态和\(f\)答案数组的维数(这个题主要就是找出来状态如何转移) 题目背景 \(BanG Dream!\)里的所有偶像乐队要一起大合唱,不过在排队上出了一些问题. ...

  8. LeetCode65. 有效数字

    这题完美的诠释了什么叫"面向测试用例编程".由于要考虑的情况很多,所以基本的思路是先根据给出的测试用例写出规则判断无效的情况,然后再根据提交的错误对剩下的情况进行特判,如果不满足所 ...

  9. WIN10有线网络反复断开解决方法

    最近家里台式机碰到一个奇怪的问题,开机之后有线网络就时断时续,右下角网络图标不停在小地球与小电脑之间切换.网上大概搜索了一下,貌似碰到这种问题的朋友不在少数,但大部分朋友碰到的都是无线网络居多.这里把 ...

  10. 浏览器缓存_HTTP强缓存和协商缓存

    浏览器缓存 浏览器缓存是浏览器在本地磁盘对用户最近请求过的文档进行存储,当访问者再次访问同一页面时,浏览器就可以直接从本地磁盘加载文档. 所以根据上面的特点,浏览器缓存有下面的优点: 减少冗余的数据传 ...