专栏首页ccf19881030的博客线程本地存储-The Boost C++ Libraries

线程本地存储-The Boost C++ Libraries

前言

The Boost C++ Libraries 本博客是Thread Local Storage的一篇译文。关于《The Boost C++ Llibraries》一书的在线完整书的目录,参见The Boost C++ Libraries,Boost库的官网地址是:https://www.boost.org/,翻译这篇博文时Boost库的最新版本是1.73.0

线程本地存储

线程本地存储(TLS)是专用存储区,只能由一个线程访问。 TLS变量可以视为仅对特定线程可见,而对整个程序不可见的全局变量。

示例44.12 使用静态变量同步多个线程

#include <boost/thread.hpp>
#include <iostream>

boost::mutex mutex;

void init()
{
  static bool done = false;
  boost::lock_guard<boost::mutex> lock{mutex};
  if (!done)
  {
    done = true;
    std::cout << "done" << '\n';
  }
}

void thread()
{
  init();
  init();
}

int main()
{
  boost::thread t[3];

  for (int i = 0; i < 3; ++i)
    t[i] = boost::thread{thread};

  for (int i = 0; i < 3; ++i)
    t[i].join();
}

例44.12在三个线程中执行一个函数thread()。 thread()调用另一个函数init()两次,并且init()检查布尔变量done是否为false。 如果是,则将变量设置为true,并将done写入标准输出。

done是所有线程共享的静态变量。 如果第一个线程将done设置为true,则第二个和第三个线程将不会将done写入标准输出。 在任何线程中第二次调用init()都不会将完成写入标准输出。 该示例将打印完成一次。

像done这样的静态变量可用于在进程中进行一次性初始化。 要对每个线程进行一次性初始化,可以使用TLS。

示例44.13 使用TLS同步多个线程

#include <boost/thread.hpp>
#include <iostream>

boost::mutex mutex;

void init()
{
  static boost::thread_specific_ptr<bool> tls;
  if (!tls.get())
  {
    tls.reset(new bool{true});
    boost::lock_guard<boost::mutex> lock{mutex};
    std::cout << "done" << '\n';
  }
}

void thread()
{
  init();
  init();
}

int main()
{
  boost::thread t[3];

  for (int i = 0; i < 3; ++i)
    t[i] = boost::thread{thread};

  for (int i = 0; i < 3; ++i)
    t[i].join();
}

在示例44.13中,静态变量done已替换为TLS变量tls,该变量基于类模板boost::thread_specific_ptr –用bool类型实例化。原则上,tls的工作方式类似于完成:它充当指示是否已完成某些操作的条件。但是,关键的区别在于,由tls存储的值仅对相应线程可见并且可用。

一旦创建了boost::thread_specific_ptr类型的变量,就可以对其进行设置。该变量需要布尔类型的变量的地址,而不是变量本身的地址。使用reset()成员函数,可以将地址存储在tls中。在示例44.13中,动态分配了bool类型的变量,并将其地址(由new返回)存储在tls中。为了避免每次调用init()时都设置tls,成员函数get()用于检查地址是否已经存储。

因为boost :: thread_specific_ptr存储一个地址,所以此类的行为类似于指针。例如,它提供了成员函数operator *和operator->,它们可以像使用指针一样工作。

示例44.13打印了三遍到标准输出。每个线程在第一次调用init()时都会完成打印。因为使用了TLS变量,所以每个线程都使用自己的变量tls。当第一个线程使用指向动态分配的布尔变量的指针初始化tls时,第二个线程和第三个线程中的tls变量仍未初始化。由于TLS变量是每个线程全局的,而不是每个进程全局的,因此在一个线程中使用tls不会更改任何其他线程中的变量。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Boost.Thread-创建和管理线程-The Boost C++ Libraries

    在Boost.Thread库中最重要的类是boost ::thread,它在boost/thread.hpp中定义。 该类用于创建新线程。 Example 44...

    ccf19881030
  • nodejs库yaml读取yml或yaml配置文件

    最近在使用TypeScript编写后台接口时,需要读取yaml配置文件,使用到了yaml这个nodejs库,其npm官网地址为:https://www.npmj...

    ccf19881030
  • 进程与线程的区别

    一、操作系统中线程和进程的概念 现在的操作系统是多任务操作系统。多线程是实现多任务的一种方式。 进程是指一个内存中运行的应用程序,每个进程都有自己独立的...

    ccf19881030
  • 数据竞争(data race)问题分析的利器——valgrind的Helgrind

            数据竞争(data race)是指在非线程安全的情况下,多线程对同一个地址空间进行写操作。一般来说,我们都会通过线程同步方法来保证数据的安全,比...

    方亮
  • WCF技术剖析之二十九:换种不同的方式调用WCF服务[提供源代码下载]

    我们有两种典型的WCF调用方式:通过SvcUtil.exe(或者添加Web引用)导入发布的服务元数据生成服务代理相关的代码和配置;通过ChannelFactor...

    蒋金楠
  • Boost.Thread-创建和管理线程-The Boost C++ Libraries

    在Boost.Thread库中最重要的类是boost ::thread,它在boost/thread.hpp中定义。 该类用于创建新线程。 Example 44...

    ccf19881030
  • 基于 Docker 和 Kubernetes 的微服务实践

    微服务 是将单一的应用程序拆分成多个微小的服务,各个小服务之间松耦合,高内聚,每个小的服务可以单独进行开发,不依赖于具体的编程语言,也可以使用不同的数据存储技术...

    Java帮帮
  • MySQL笔记汇总

    官方文档:https://dev.mysql.com/doc/refman/8.0/en/

    Noneplus
  • 分布式事务的实现方法及替代方案

    图的上半是两阶段提交成功的演示, 下半是两阶段提交失败的演示. 关于两阶段提交网上有很多经典的讲解, 这里就不细说了

    java思维导图
  • 基于 Redis 的分布式锁

    分布式锁在分布式应用中应用广泛,想要搞懂一个新事物首先得了解它的由来,这样才能更加的理解甚至可以举一反三。

    Java知音

扫码关注云+社区

领取腾讯云代金券