C++——多线程编程(一)std::thread

C++ 多线程编程系列一:线程管理(std::thread 对象、join、detach、传参、不可拷贝性、所有权转移) 每个 C++ 程序至少有一个线程,并且是由 C++ 运行时启动的,这个线程的线程函数就是 函数。你可以在这个线程中再启动其他线程。 的构造函数申明如下: 线程的启动 C++ 标准库提供了 以支持多线程编程。这里先介绍通过初始化构造函数创建 对象的方式启动线程。例如: 创建了一个 对象 ,并指定了线程函数 ,随机即启动了线程。 会阻塞到线程函数执行完成。线程任务可以是任意的可调用类型(callable type)。可调用类型包括:例如,可调用类型为仿函数时: 但是,这个时候需要注意下面启动线程的方式 阅读详情

转载自:https://blog.youkuaiyun.com/shanshangyouzhiyangM/article/details/52986185

(一)与C++11多线程相关的头文件

C++11 新标准中引入了四个头文件来支持多线程编程,他们分别是< atomic> ,< thread>,< mutex>,< condition_variable>和< future>。 
•< atomic>:该头文主要声明了两个类, std::atomic 和 std::atomic_flag,另外还声明了一套 C 风格的原子类型和与 C 兼容的原子操作的函数。 
•< thread>:该头文件主要声明了 std::thread 类,另外 std::this_thread 命名空间也在该头文件中。 
•< mutex>:该头文件主要声明了与互斥量(mutex)相关的类,包括 std::mutex 系列类,std::lock_guard, std::unique_lock, 以及其他的类型和函数。 
•< condition_variable>:该头文件主要声明了与条件变量相关的类,包括 std::condition_variable 和 std::condition_variable_any。 
•< future>:该头文件主要声明了 std::promise, std::package_task 两个 Provider 类,以及 std::future 和 std::shared_future 两个 Future 类,另外还有一些与之相关的类型和函数,std::async() 函数就声明在此头文件中。

(二)std::thread

0

0.1 线程状态

在一个线程的生存期内,可以在多种状态之间转换,不同的操作系统可以实现不同的线程模型,定义许多不同的线程状态,每个状态还可以包含多个子状态,但大体来说,如下几种状态是通用的:

1)就绪:参与调度,等待被执行,一旦被调度选中,立即开始执行

2)运行:占用CPU,正在运行中

3)休眠:暂不参与调度,等待特定事件发生

4)中止:已经运行完毕,等待回收线程资源

0.2 线程环境

线程存在于进程之中,进程内所有全局资源对于内部每个线程都是可见的。

进程内典型全局资源如下:

1)代码区:这意味着当前进程空间内所有的可见的函数代码,对于每个线程来说,也是可见的

2)静态存储区:全局变量,静态空间

3)动态存储区:堆空间

线程内典型的局部资源:

1)本地栈空间:存放本线程的函数调用栈,函数内部的局部变量等

2)部分寄存器变量:线程下一步要执行代码的指针偏移量

1 构造、赋值和拷贝

1.1 构造函数

(1)default :thread() noexcept; 
(2)initialization :template < class Fn, class… Args> explicit thread (Fn&& fn, Args&&… args); 
(3)copy [deleted] :thread (const thread&) = delete; 
(4)move :thread (thread&& x) noexcept;

  1. 默认构造函数,创建一个空的 thread 执行对象。
  2. 初始化构造函数,创建一个 thread对象,该 thread对象可被joinable,新产生的线程会调用 fn 函数,该函数的参数由 args 给出。
  3. 拷贝构造函数(被禁用),意味着 thread 不可被拷贝构造。
  4. move 构造函数,调用成功之后 x 不代表任何 thread 执行对象。

注意:可被 joinable 的 thread 对象必须在他们销毁之前被主线程 join 或者将其设置为 detached。

栗子:

#include <iostream>
#include <utility>
#include <thread>
#include <chrono>
#include <functional>
#include <atomic>

void f1(int n)
{
    for (int i = 0; i < 5; ++i) 
    {
        std::cout << "Thread " << n << " executing\n";
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}

void f2(int& n)
{
    for (int i = 0; i < 5; ++i) {
        std::cout << "Thread 2 executing\n";
        ++n;
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}

int main()
{
    int n = 0;
    std::thread t1; // t1 is not a thread
    std::thread t2(f1, n + 1); // pass by value
    std::thread t3(f2, std::ref(n)); // pass by reference
    std::thread t4(std::move(t3)); // t4 is now running f2(). t3 is no longer a thread
    t2.join();
    t4.join();
    std::cout << "Final value of n is " << n << '\n';
}

注意:关于 std::ref 请参考http://tieba.baidu.com/p/1292003201、https://zhidao.baidu.com/question/1240776856100751219.html

Possible output: 

Thread 1 executing
Thread 2 executing
Thread 1 executing
Thread 2 executing
Thread 1 executing
Thread 2 executing
Thread 1 executing
Thread 2 executing
Thread 2 executing
Thread 1 executing
Final value of n is 5

1.2 MOVE赋值操作

move (1):thread& operator= (thread&& rhs) noexcept; 
copy [deleted] (2):thread& operator= (const thread&) = delete;

  1. move 赋值操作,如果当前对象不可 joinable,需要传递一个右值引用(rhs)给 move 赋值操作;如果当前对象可被 joinable,则 terminate() 报错。 
    注意:关于右值引用请参考文章http://www.ibm.com/developerworks/cn/aix/library/1307_lisl_c11/
  2. 拷贝赋值操作被禁用,thread 对象不可被拷贝。
//#include <stdio.h>
//#include <stdlib.h>

#include <chrono>    // std::chrono::seconds
#include <iostream>  // std::cout
#include <thread>    // std::thread, std::this_thread::sleep_for

void thread_task(int n) {
    std::this_thread::sleep_for(std::chrono::seconds(n));
    std::cout << "hello thread "
        << std::this_thread::get_id()
        << " paused " << n << " seconds" << std::endl;
}

/*
* ===  FUNCTION  =========================================================
*         Name:  main
*  Description:  program entry routine.
* ========================================================================
*/
int main(int argc, const char *argv[])
{
    std::thread threads[5];
    std::cout << "Spawning 5 threads...\n";
    for (int i = 0; i < 5; i++) {
        threads[i] = std::thread(thread_task, i + 1); /******copy********/
    }
    std::cout << "Done spawning threads! Now wait for them to join\n";
    for (auto& t : threads) {
        t.join();
    }
    std::cout << "All threads joined.\n";

    system("pause");
    return EXIT_SUCCESS;
}  /* ----------  end of function main  ---------- */

注意:C++11中的for循环语句http://blog.youkuaiyun.com/hackmind/article/details/24271949

2 其他成员函数

2.1 get_id :获取线程 ID。

参数:none 
返回值:An object of member type thread::id that uniquely identifies the thread (if joinable), or default-constructed (if not joinable)

Returns the thread id.

If the thread object is joinable, the function returns a value that uniquely identifies the thread.

If the thread object is not joinable, the function returns a default-constructed object of member type thread::id.

栗子:

// thread::get_id / this_thread::get_id
#include <iostream>       // std::cout
#include <thread>         // std::thread, std::thread::id, std::this_thread::get_id
#include <chrono>         // std::chrono::seconds

std::thread::id main_thread_id = std::this_thread::get_id();

void is_main_thread() {
  if ( main_thread_id == std::this_thread::get_id() )
    std::cout << "This is the main thread.\n";
  else
    std::cout << "This is not the main thread.\n";
}

int main() 
{
  is_main_thread();
  std::thread th (is_main_thread);
  th.join();
}

output:

This is the main thread.
This is not the main thread.

2.2 joinable :检查线程是否可被 join。

返回值:false、true 
参数:none

Returns whether the thread object is joinable.

A thread object is joinable if it represents a thread of execution.

A thread object is not joinable in any of these cases: 
•if it was default-constructed. 
•if it has been moved from (either constructing another thread object, or assigning to it). 
•if either of its members join or detach has been called.

栗子:

// example for thread::joinable
#include <iostream>       // std::cout
#include <thread>         // std::thread

void mythread() 
{
  // do stuff...
}

int main() 
{
  std::thread foo;
  std::thread bar(mythread);

  std::cout << "Joinable after construction:\n" << std::boolalpha;
  std::cout << "foo: " << foo.joinable() << '\n';
  std::cout << "bar: " << bar.joinable() << '\n';

  if (foo.joinable()) foo.join();
  if (bar.joinable()) bar.join();

  std::cout << "Joinable after joining:\n" << std::boolalpha;
  std::cout << "foo: " << foo.joinable() << '\n';
  std::cout << "bar: " << bar.joinable() << '\n';

  return 0;
}

Output (after 3 seconds):

Joinable after construction:
foo: false
bar: true
Joinable after joining:
foo: false
bar: false

2.3 join:Join 线程。

参数:none 
返回值:none

The function returns when the thread execution has completed.

直到线程函数被执行完毕,join才返回。This synchronizes the moment this function returns with the completion of all the operations in the thread: This blocks the execution of the thread that calls this function until the function called on construction returns (if it hasn’t yet).

After a call to this function, the thread object becomes non-joinable and can be destroyed safely.

栗子:

// example for thread::join
#include <iostream>       // std::cout
#include <thread>         // std::thread, std::this_thread::sleep_for
#include <chrono>         // std::chrono::seconds

void pause_thread(int n) 
{
  std::this_thread::sleep_for (std::chrono::seconds(n));
  std::cout << "pause of " << n << " seconds ended\n";
}

int main() 
{
  std::cout << "Spawning 3 threads...\n";
  std::thread t1 (pause_thread,1);
  std::thread t2 (pause_thread,2);
  std::thread t3 (pause_thread,3);
  std::cout << "Done spawning threads. Now waiting for them to join:\n";
  t1.join();
  t2.join();
  t3.join();
  std::cout << "All threads joined!\n";

  return 0;
}

Output (after 3 seconds):

Spawning 3 threads...
Done spawning threads. Now waiting for them to join:
pause of 1 seconds ended
pause of 2 seconds ended
pause of 3 seconds ended
All threads joined!

2.4 detach:Detach 线程

参数:none 
返回值:none

Detaches the thread represented by the object from the calling thread, allowing them to execute independently from each other.

Both threads continue without blocking nor synchronizing in any way. Note that when either one ends execution, its resources are released.

After a call to this function, the thread object becomes non-joinable and can be destroyed safely.

栗子:

#include <iostream>       // std::cout
#include <thread>         // std::thread, std::this_thread::sleep_for
#include <chrono>         // std::chrono::seconds

void pause_thread(int n) 
{
  std::this_thread::sleep_for (std::chrono::seconds(n));
  std::cout << "pause of " << n << " seconds ended\n";
}

int main() 
{
  std::cout << "Spawning and detaching 3 threads...\n";
  std::thread (pause_thread,1).detach();
  std::thread (pause_thread,2).detach();
  std::thread (pause_thread,3).detach();
  std::cout << "Done spawning threads.\n";

  std::cout << "(the main thread will now pause for 5 seconds)\n";
  // give the detached threads time to finish (but not guaranteed!):
  pause_thread(5);
  return 0;
}

Output (after 5 seconds):

Spawning and detaching 3 threads...
Done spawning threads.
(the main thread will now pause for 5 seconds)
pause of 1 seconds ended
pause of 2 seconds ended
pause of 3 seconds ended
pause of 5 seconds ended

detach调用之后,目标线程就成为了守护线程,驻留后台运行,与之关联的std::thread对象失去对目标线程的关联,无法再通过std::thread对象取得该线程的控制权。当线程主函数执行完之后,线程就结束了,运行时库负责清理与该线程相关的资源。

当一个thread对象到达生命期终点而关联线程还没有结束时,则thread对象取消与线程之间的关联,目标线程线程则变为分离线程继续运行搜索。

当调用join函数时,调用线程阻塞等待目标线程终止,然后回收目标线程的资源。

2.5 swap:Swap 线程 。

参数:the thread to swap with  
返回值:none

Exchanges the underlying handles of two thread objects

栗子

#include <iostream>
#include <thread>
#include <chrono>

void foo()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

void bar()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

int main()
{
    std::thread t1(foo);
    std::thread t2(bar);

    std::cout << "thread 1 id: " << t1.get_id() << std::endl;
    std::cout << "thread 2 id: " << t2.get_id() << std::endl;

    std::swap(t1, t2);

    std::cout << "after std::swap(t1, t2):" << std::endl;
    std::cout << "thread 1 id: " << t1.get_id() << std::endl;
    std::cout << "thread 2 id: " << t2.get_id() << std::endl;

    t1.swap(t2);

    std::cout << "after t1.swap(t2):" << std::endl;
    std::cout << "thread 1 id: " << t1.get_id() << std::endl;
    std::cout << "thread 2 id: " << t2.get_id() << std::endl;

    t1.join();
    t2.join();
}

Possible output: 

thread 1 id: 1892
thread 2 id: 2584
after std::swap(t1, t2):
thread 1 id: 2584
thread 2 id: 1892
after t1.swap(t2):
thread 1 id: 1892
thread 2 id: 2584

另外:void std::swap( thread &lhs, thread &rhs ); 
说明:不是成员函数。只是重载了std::swap函数。 
用法:std::swap(thread1,thread2); 
栗子:

#include <iostream>
#include <thread>
#include <chrono>

void foo()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

void bar()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

int main()
{
    std::thread t1(foo);
    std::thread t2(bar);

    std::cout << "thread 1 id: " << t1.get_id() << std::endl;
    std::cout << "thread 2 id: " << t2.get_id() << std::endl;

    std::swap(t1, t2);

    std::cout << "after std::swap(t1, t2):" << std::endl;
    std::cout << "thread 1 id: " << t1.get_id() << std::endl;
    std::cout << "thread 2 id: " << t2.get_id() << std::endl;

    t1.swap(t2);

    std::cout << "after t1.swap(t2):" << std::endl;
    std::cout << "thread 1 id: " << t1.get_id() << std::endl;
    std::cout << "thread 2 id: " << t2.get_id() << std::endl;

    t1.join();
    t2.join();
}

输出:

thread 1 id: 1892
thread 2 id: 2584
after std::swap(t1, t2):
thread 1 id: 2584
thread 2 id: 1892
after t1.swap(t2):
thread 1 id: 1892
thread 2 id: 2584

2.6 native_handle:返回 native handle。

2.7 hardware_concurrency [static]:检测硬件并发特性。

2.8 总结

http://en.cppreference.com/w/cpp/thread/thread

std::thread m_thrSend; //线程句柄
bool m_sending{ false }; //线程退出标识
bool startSend()
    {
        if (m_sending)
            return false;
        m_sending = true;
        m_thrSend = std::thread([this](){this->thrSend(); });
        return true;
    }
void stopSend()
    {
        m_sending = false;
        std::this_thread::sleep_for(std::chrono::milliseconds(50));
        if (m_thrSend.joinable())
            m_thrSend.join();
    }
C++11 多线程支持之std::thread 从C++11开始,C++标准库已经支持了线程库了,其实在底层,仍旧使用的是平台相关的线程API 有了std::thread之后,我们就不用在不同的平台使用不同的API了,比如Unix平台使用pthread, windows平台使用WinSDK的CreateThread了,接口使用去掉了平台差异性,使得项目开发具有更好的移植性1. std::thread的使用方法A. 所需头文件#include < 阅读详情

相关推荐

基于C++11并发库的线程池与消息队列多线程框架——std::thread类

1 前言  C++11标准在标准库中为多线程提供了组件,这意味着使用C++编写与平台无关的多线程程序成为可能,而C++程序的可移植性也得到了有力的保证。    在之前我们主要使用的多线程库要么是属于某个单独平台的,例如:POSIX线程库(Linux),Windows线程库(Windows),还有第三方数据库:Boost线程库。但是且不说性能上的不同,它们都有各自缺点,要么受平台限制无法系统间移植...

godqiao的博客 1万+

std::thread创建一个带this 的线程

thread

sunfanup的博客 514

高效并行计算:使用C++中的std::thread实现多线程编程

在现代计算中,随着多核处理器的普及,如何充分利用硬件资源以提升程序性能成为关键问题之一。C++标准库提供了丰富的多线程支持,其中`std::thread`是用于实现并发计算的核心工具之一。通过合理的多线程设计,程序可以实现并行计算,显著缩短任务执行时间。本文将详细讨论如何在C++中使用`std::thread`进行多线程编程,涵盖线程的创建、同步、资源共享、数据竞争问题等关键内容,并通过代码示例演示如何通过并行计算提升性能。最终,我们将分析多线程编程中的性能调优和最佳实践。

一个被知识诅咒的人 1403

std::thread和std::this_thread的详细说明

std::thread类来表示执行的各个线程。执行线程是实际上是执行一系列指令,可以在多线程环境中与其他此类序列同时执行,同时共享相同的地址空间。 std::this_thread命名空间包含了对当前线程的一些基本操作,如获取当前线程id、休眠当前线程、让渡当前线程的时间片给其他线程等。

咸鱼爱幻想的博客 5804

C++多线程编程:深入剖析std::thread的使用方法

C++11 thread的语法、构造函数、主要成员函数、简单线程的创建详解。 介绍线程封装。更多函数std::this_thread、std::this_thread::get_id()、std::this_thread::yield()、std::this_thread::sleep_for等的使用。

Lion_Long的博客 9716

C++ linux 睡眠函数sleep和std::this_thread::sleep_for

linux下支持,需要引入头文件unistd.h #include <iostream> #include <unistd.h> using namespace std; int main() { //5秒后输出Hi,Gril! sleep(5); std::cout << "Hi,Gril!" << std::endl; //3000000微妙(相当于3秒)输出Hi,Boy! usleep(3000000); std::cout <&lt

小勇博客 3906

std::this_thread

std::this_thread

darren_pty 559

C++ std::thread多线程编程实践指南

在多线程编程中,共享数据的安全访问是一个至关重要的问题。当多个线程试图同时读写同一数据时,就会出现竞争条件,可能会导致数据不一致。为了解决这个问题,C++标准库提供了互斥量(mutex),它是一种同步工具,用于保护共享资源的访问。互斥量可以用来保证一段代码在同一时刻只被一个线程执行。它通常用于以下几个目的:防止多个线程同时访问同一个资源(临界区)。保证共享资源的一致性。防止因并发执行而产生的竞争条件。标准库中的std::mutex。

weixin_31569663的博客 1106

C++ 多线程编程(一):std::thread的使用

说到多线程编程,就不得不提并行和并发,多线程是实现并发和并行的一种手段。并行是指两个或多个独立的操作同时进行。并发是指一个时间段内执行多个操作。在单核时代,多个线程是并发的,在一个时间段内轮流执行;在多核时代,多个线程可以实现真正的并行,在多核上真正独立的并行执行。例如现在常见的4核4线程可以并行4个线程;4核8线程则使用了超线程技术,把一个物理核模拟为2个逻辑核心,可以并行8个线程。C++11之前,window和linux平台分别有各自的多线程标准,使用C++编写的多线程往往是依赖于特定平台的。

海纳百川,有容乃大。 2万+

An example: 2D immersed boundary lattice Boltzmann method code--By Timm Krüger.2011.

//谢谢Timm Krüger大佬的代码。 还是老样子,有啥问题Feel free to tell us~毕竟群众力量大嘛~QQ群:293267908。 // 话不多说,上干货! // ISBN 978-3-319-44649-3 (Electronic) // 978-3-319-44647-9 (Print) // http://www.springer.c...

weixin_37783345的博客 1418

描述符链表(Descriptor Chain)是什么?

描述符链表是硬件加速数据传输的核心数据结构,通过链式描述符(包含地址、长度、控制标志等)实现DMA自动批量处理,显著降低CPU负载。其工作原理为:CPU初始化链表后,硬件按序处理每个描述符,完成自动跳转与中断通知。在网卡收包、NVMe存储等场景中应用广泛,优势包括批处理、低延迟和灵活调度。需注意内存对齐、缓存一致性等实现细节,优化手段包括预分配描述符池、环形缓冲区等。该技术是网络/存储领域提升吞吐量的关键方案。

guigenyi的专栏 772

C++11 多线程(std::thread)详解

本文介绍了C++11标准库中的std::thread多线程编程基础。

jcShan709的博客 15万+

ADS笔记,新旧两组仿真数据进行绘图和列表对比

原理图器件参数的不同,怎么进行对比观看,操作如下。

彭辉荣的博客 3867

【C++ 与Qt 线程】C++ std::thread 与Qt qthread多线程混合编程

C++与Qt深度融合:高效设计多线程应用框架

探索C++编程的奥秘,分享深入的技术见解和实践,旨在激发读者创造力与解决问题的思维。 5357

从零到一:在RK3588 Android12上实战RTL8723DU WiFi蓝牙双模驱动移植

本文详细介绍了在RK3588 Android12系统上实战RTL8723DU WiFi蓝牙双模驱动移植的全过程。从驱动源码获取与修改、系统级集成与编译,到调试与性能优化,提供了完整的解决方案。特别针对USB接口适配、电源管理和蓝牙共存等关键问题给出了具体代码示例,帮助开发者快速完成驱动适配并提升设备稳定性。

weixin_28703489的博客 324

weblogic等保测评操作过程

weblogic网络安全等级测评保护操作

qq_48257021的博客 2756

【C++】多线程(一):std::thread的使用

这篇文章应我朋友的邀请,写一篇文章介绍下C++多线程。

矢车菊二十七号 2067

433MHz无线通信避坑指南:如何解决信号干扰和误码问题

本文深入探讨433MHz无线通信中的信号干扰和误码问题,提供从射频前端设计到协议优化的全链路解决方案。通过天线匹配、电源噪声抑制、曼彻斯特编码改进及实时频点切换等技术,显著提升通信稳定性和距离。适合智能家居和工业无线控制系统的开发者参考。

weixin_29288313的博客 415
上一篇: 给出n求1/n=1/x+1/y(n,x,y=1,2,3...)的解的个数,
下一篇: 将一个二维数组排序到一维数组
xy_cpp
博客等级 码龄10年 119粉丝 84原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值