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

(一)与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/1292003201https://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.csdn.net/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();
    }
时间: 2024-08-25 10:40:36

C++——多线程编程(一)std::thread的相关文章

IOS开发-多线程编程技术(Thread、Cocoa operations、GCD)

前言:在软件开发中,多线程编程技术被广泛应用,相信多线程任务对我们来说已经不再陌生了.有了多线程技术,我们可以同做多个事情,而不是一个一个任务地进行.比如:前端和后台作交互.大任务(需要耗费一定的时间和资源)等等.也就是说,我们可以使用线程把占据时间长的任务放到后台中处理,而不影响到用户的使用. 线程的定义: 每个正在系统上运行的程序都是一个进程.每个进程包含一到多个线程.进程也可能是整个程序或者是部分程序的动态执行.线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行.也可以把它理

c++11多线程记录1 -- std::thread

启动一个线程 话不多说,直接上代码 void func(); int main() { std::thread t(func); //这里就开始启动线程了 return 0; } void func() { std::cout << "Hello, " << std::this_thread::get_id() << std::endl; } 等待子线程结束 有时候开启一个子线程之后,父线程很快运行结束: 如果想要父线程做完自己的工作之后等待子线程运

.NET多线程编程

在.NET多线程编程这个系列我们讲一起来探讨多线程编程的各个方面.首先我将在本篇文章的开始向大家介绍多线程的有关概念以及多线程编程的基础知识;在接下来的文章中,我将逐一讲述.NET平台上多线程编程的知识,诸如System.Threading命名空间的重要类以及方法,并就一些例子程序来作说明. 引言 早期的计算硬件十分复杂,但是操作系统执行的功能确十分的简单.那个时候的操作系统在任一时间点只能执行一个任务,也就是同一时间只能执行一个程序.多个任务的执行必须得轮流执行,在系统里面进行排队等候.由于计

Java多线程编程要点

Java多线程编程要点 认识Thread和Runnable Java中 实现多线程有两种途径:继承Thread类或者实现Runnable接口.Runnable是接口,建议用接口的方式生成线程,因为接口可以实现多继承, 况且Runnable只有一个run方法,很适合继承.在使用Thread的时候只需继承Thread,并且new一个实例出来,调用 start()方法即可以启动一个线程. Thread Test = new Thread(); Test.start(); 在使用Runnable的时候需

C++使用thread类多线程编程

转自:C++使用thread类多线程编程 C++11中引入了一个用于多线程操作的thread类,下面进行简单演示如何使用,以及如果进行多线程同步. thread简单示例 #include <iostream> #include <thread> #include <Windows.h> using namespace std; void thread01() { for (int i = 0; i < 5; i++) { cout << "T

C++使用thread类进行多线程编程

C++11中引入了一个用于多线程操作的thread类,简单多线程示例: #include <iostream> #include <thread> #include <Windows.h> using namespace std; void thread01() { for (int i = 0; i < 5; i++) { cout << "Thread 01 is working !" << endl; Sleep(

C++11多线程std::thread的简单使用

转自:http://blog.csdn.net/star530/article/details/24186783 在cocos2dx 2.0时代,我们使用的是pthread库,是一套用户级线程库,被广泛地使用在跨平台应用上.但在cocos2dx 3.0中并未发现有pthread的支持文件,原来c++11中已经拥有了一个更好用的用于线程操作的类std::thread.cocos2dx 3.0的版本默认是在vs2012版本,支持c++11的新特性,使用std::thread来创建线程简直方便. 下面

java多线程编程中实现Runnable接口方法相对于继承Thread方法的优势

 java多线程创建方法http://blog.csdn.net/cjc211322/article/details/24999163  java创建多线程方法之间的区别http://blog.csdn.net/cjc211322/article/details/25000449 java多线程编程中实现Runnable接口方法相对于继承Thread方法的优势

Cocos2dx 3.0 过渡篇(二十七)C++11多线程std::thread的简单使用(下)

本篇接上篇继续讲:上篇传送门:http://blog.csdn.net/star530/article/details/24186783 简单的东西我都说的几乎相同了,想挖点深的差点把自己给填进去. 以下实际演练一下.请同意我參考偶尔E往事的一篇线程的博客, 他用的是pThread.这里我就用std::thread. 1.售票孙鑫老师的C++和Java多线程售票也一直让我念念不忘(好吧,我承认我没看过).这里用cocos2d-x3.0和C++11的std::thread实现一个吧.总共同拥有10