线程学习二:std::thread与pthread对比

1. std::thread与pthread对比

std::thread是C++11接口,使用时需要包含头文件#include <thread>,编译时需要支持c++11标准。thread中封装了pthread的方法,所以也需要链接pthread库

pthread是C++98接口且只支持Linux,使用时需要包含头文件#include <pthread.h>,编译时需要链接pthread库

std::thread对比于pthread的优缺点:

优点:

1. 简单,易用

2. 跨平台,pthread只能用在POSIX系统上(其他系统有其独立的thread实现)

3. 提供了更多高级功能,比如future

4. 更加C++(跟匿名函数,std::bind,RAII等C++特性更好的集成)

缺点:

1. 没有RWlock。有一个类似的shared_mutex,不过它属于C++14,你的编译器很有可能不支持。

2. 操作线程和Mutex等的API较少。毕竟为了跨平台,只能选取各原生实现的子集。如果你需要设置某些属性,需要通过API调用返回原生平台上的对应对象,再对返回的对象进行操作。

2. std::thread简介

2.1 std::thread构造函数

默认构造函数,创建一个空的 std::thread 执行对象。

初始化构造函数,创建一个 std::thread 对象,该 std::thread 对象可被 joinable,新产生的线程会调用 fn 函数,该函数的参数由 args 给出。

拷贝构造函数(被禁用),意味着 std::thread 对象不可拷贝构造。

Move 构造函数,move 构造函数(move 语义是 C++11 新出现的概念,详见附录),调用成功之后 x 不代表任何 std::thread 执行对象。

注意:可被 joinable 的 std::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';
}
// 编译: g++ -g test.cpp -o test -std=c++11 -lpthread

/*结果:
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 1 executing
Thread 2 executing
Final value of n is 5
*/

2.2 std::thread其他函数

get_id: 获取线程 ID,返回一个类型为 std::thread::id 的对象。

joinable: 检查线程是否可被 join。检查当前的线程对象是否表示了一个活动的执行线程,由默认构造函数创建的线程是不能被 join 的。另外,如果某个线程 已经执行完任务,但是没有被 join 的话,该线程依然会被认为是一个活动的执行线程,因此也是可以被 join 的。

detach: Detach 线程。 将当前线程对象所代表的执行实例与该线程对象分离,使得线程的执行可以单独进行。一旦线程执行完毕,它所分配的资源将会被释放。

swap: Swap 线程,交换两个线程对象所代表的底层句柄(underlying handles)。

native_handle: 返回 native handle(由于 std::thread 的实现和操作系统相关,因此该函数返回与 std::thread 具体实现相关的线程句柄,例如在符合 Posix 标准的平台下(如 Unix/Linux)是 Pthread 库)。

hardware_concurrency [static]: 检测硬件并发特性,返回当前平台的线程实现所支持的线程并发数目,但返回值仅仅只作为系统提示(hint)。

实例:

#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));
}

void independentThread() 
{
    std::cout << "Starting concurrent thread." << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout << "Exiting concurrent thread." << std::endl;
}

int main()
{
    /*************** 1. get_id()实例 *********************/
    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 << std::endl;
    std::cout << "t2's id: " << t2_id << std::endl;
    t1.join();
    t2.join();
    /*输出
        t1's id: 140097921648384
        t2's id: 140097913255680
    */

    /*************** 2. joinable()/join()实例 *********************/
    std::thread t;
    std::cout << "before starting, joinable: " << t.joinable() << std::endl;
    t = std::thread(foo);
    std::cout << "after starting, joinable: " << t.joinable() << std::endl;
    // Join 线程,调用该函数会阻塞当前线程,直到由 *this 所标示的线程执行完毕 join 才返回。
    t.join();
    /*输出
        before starting, joinable: 0
        after starting, joinable: 1
    */

    /*************** 3. detach()实例 *********************/
    std::thread t3(independentThread);
    t3.detach();
    std::this_thread::sleep_for(std::chrono::seconds(5));
    /*输出。PS:如果不加上面这一行,会出现t3还没完成,主线程就结束了
        Starting concurrent thread.
        Exiting concurrent thread.
    */

    /*************** 4. swap实例 *********************/
    std::thread t4(foo);
    std::thread t5(bar);
    std::cout << "thread 4 id: " << t4.get_id() << std::endl;
    std::cout << "thread 5 id: " << t5.get_id() << std::endl;
    std::swap(t4, t5);
    std::cout << "after std::swap(t4, t5):" << std::endl;
    std::cout << "thread 4 id: " << t4.get_id() << std::endl;
    std::cout << "thread 5 id: " << t5.get_id() << std::endl;
    t4.swap(t5);
    std::cout << "after t4.swap(t5):" << std::endl;
    std::cout << "thread 4 id: " << t4.get_id() << std::endl;
    std::cout << "thread 5 id: " << t5.get_id() << std::endl;
    t4.join();
    t5.join();
    /*输出
        thread 4 id: 139705731315456
        thread 5 id: 139705739708160
        after std::swap(t4, t5):
        thread 4 id: 139705739708160
        thread 5 id: 139705731315456
        after t4.swap(t5):
        thread 4 id: 139705731315456
        thread 5 id: 139705739708160
    */

    return 0;
}

// g++ -g test.cpp -o test -std=c++11 -lpthread

2.3 std::this_thread 命名空间中相关辅助函数介绍

get_id: 获取线程 ID。

yield: 当前线程放弃执行,操作系统调度另一线程继续执行。

sleep_until: 线程休眠至某个指定的时刻(time point),该线程才被重新唤醒。

sleep_for: 线程休眠某个指定的时间片(time span),该线程才被重新唤醒,不过由于线程调度等原因,实际休眠时间可能比 sleep_duration 所表示的时间片更长。

实例

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

std::mutex g_display_mutex;

void foo()
{
    std::thread::id this_id = std::this_thread::get_id();

    g_display_mutex.lock();
    std::cout << "thread " << this_id << " sleeping..." << std::endl;
    g_display_mutex.unlock();

    std::this_thread::sleep_for(std::chrono::seconds(1));
}

// "busy sleep" while suggesting that other threads run 
// for a small amount of time
void little_sleep(std::chrono::microseconds us)
{
  auto start = std::chrono::high_resolution_clock::now();
  auto end = start + us;
  do {
      std::this_thread::yield();
  } while (std::chrono::high_resolution_clock::now() < end);
}

int main()
{
    /********************* 1. std::this_thread::get_id()实例 *********************/
    std::thread t1(foo);
    std::thread t2(foo);
    t1.join();
    t2.join();
    /*结果:
        thread 140251680864000 sleeping...
        thread 140251672471296 sleeping...
    */

    /********************* 2. std::this_thread::yield()实例 *********************/
    auto start = std::chrono::high_resolution_clock::now();

    little_sleep(std::chrono::microseconds(100));

    auto elapsed = std::chrono::high_resolution_clock::now() - start;
    std::cout << "waited for "
              << std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count()
              << " microseconds" << std::endl;
    /*结果:
        waited for 102 microseconds
    */

    /********************* 3. std::this_thread::sleep_for实例 *********************/
    std::cout << "Hello waiter" << std::endl;
    std::chrono::milliseconds dura( 2000 );
    std::this_thread::sleep_for( dura );
    std::cout << "Waited 2000 ms" << std::endl;
    /*结果:
        Hello waiter
        Waited 2000 ms
    */
    return 0;
}
// g++ -g test.cpp -o test -std=c++11 -lpthread

3. pthread简介

pthread_create 创建线程

pthread_exit 终止线程

pthread_join 连接线程

pthread_detach 分离线程

https://www.runoob.com/w3cnote/cpp-std-thread.html
https://www.runoob.com/cplusplus/cpp-multithreading.html

原文链接: https://www.cnblogs.com/vivian187/p/15958851.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    线程学习二:std::thread与pthread对比

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/396725

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月7日 上午9:08
下一篇 2023年4月7日 上午9:08

相关推荐