【问题标题】:Is it safe to mix pthread.h and C++11 standard library threading features?混合 pthread.h 和 C++11 标准库线程功能是否安全?
【发布时间】:2013-02-28 08:45:47
【问题描述】:

我可以使用pthread_create 生成一个线程并在其中安全地使用std::mutex 吗?

我认为如果 std::mutex 被实现为 pthread_mutex_t 那就没问题了,但我在任何地方都没有看到这一点

例如:

#include <pthread.h>
#include <mutex>

namespace {
std::mutex global_lock;
}

void* thread_func(void* vp) {
    // std::mutex used in thread spawned with pthread_create
    std::lock_guard<std::mutex> guard(global_lock);
    // critical section
    return nullptr;
}

int main() {
    pthread_t tid;
    pthread_create(&tid, nullptr, thread_func, nullptr);
    pthread_join(tid, NULL);
}

顺便说一句,我正在运行 Debian Wheezy。

【问题讨论】:

  • 生成线程和锁定互斥锁是两个独立的概念。您的问题实际上是关于混合来自 STL 和 PThread 的并发控制,还是特别是这一个实例?
  • @sixlettervariables 的一般混合控制。
  • 您能详细说明一下需求/用例吗?您是否需要从 C API 中运行代码?对于这种情况,这可能没问题(因为使用 pthread 运行的 C API 需要基于 pthread 的 C++ 实现)。
  • @g-makulik 我不确定我是否明白你在问什么。我的特定用例并不像我关心的那样多,因为它们是否可以在一般情况下混合使用。我不打算使用任何 C API。让我们一直假设 C++11。

标签: c++ c++11 pthreads mutex


【解决方案1】:

你可以在我的机器上(Debian 也是)。但我不确定我是否会称之为保险箱。

如果您查看相关文件,在我的例子中为/usr/include/c++/4.7/i486-linux-gnu/bits/gthr-default.h,您会看到与 pthreads api 的 1:1 映射。 &lt;mutex&gt; 使用 __gthread_mutex_lock 进行锁定,该锁定在 pthread_mutex_lock 中完全定义。或者你会看到std::thread 声明typedef __gthread_t native_handle_type;

我不知道是否有记录的方法来检查是否使用了 pthread。但是gthr-default.h_GLIBCXX_GCC_GTHR_POSIX_H 定义为包含保护,我认为只要定义了这个宏,您就可以假设您可以将它们混合使用。

编辑:鉴于@Wakely 的提示,我会写:

template <typename T>
using strip = typename std::remove_pointer<typename std::decay<T>::type>::type;

static_assert(std::is_same<strip<std::thread::native_handle_type>, pthread_t>::value,
              "libstdc++ doesn't use pthread_t");

【讨论】:

  • 不要依赖像那个宏这样的实现细节,它可能会改变下一个版本(最近破坏了 Boost.Thread。)std::is_same&lt;std::thread::native_handle_type, pthread_t&gt; 是使用 Pthreads 的一个很好的指标,尽管native_handle_type可能是pthread_t* 或其他相关类型,测试将失败
  • 看起来 native_handle_type 不是指针,它是我平台上 gcc 上的 pthread_t,所以不需要 strip 部分(但仍然很酷,我没有知道你能做到)。
【解决方案2】:

任何规范都没有保证它会起作用,但很可能任何在使用 pthreads 作为其唯一真正线程库的操作系统上的 C++ 实现都将在 C++ 线程下使用 pthreads,因此它可能会起作用。

如果您稍后尝试将代码移植到使用非 pthread 的其他平台,即使该平台也支持 pthread(例如 windows),您可能会遇到问题。

问题是,为什么要麻烦和冒险呢?如果您使用的是 C++11 std::mutex,为什么不同时使用 std::thread

【讨论】:

  • 我可能不会冒险,但我想也许它会被认为是安全的。想要这个的原因是人为的。但是让我们假设我正在使用现有的 C++ 代码并对其进行更新。感谢您的回答。
  • 何必呢?因为pthread_create 支持通过pthread_attr_t 进行自定义,而std::thread 不支持
  • 即使 C++11 线程实现不基于 pthreads,任何同时具有这两种 API 的平台都很可能根据通用的底层平台 API 来实现它们。尽管缺乏保证,但我认为对实际可移植性有合理的期望。我认为缺乏实​​现其中一个或另一个的平台将比实现两个不兼容的 API 的平台更常见。
  • std::thread 不提供任何方式来设置或控制堆栈大小。因此,如果你想这样做,你需要编写不可移植的代码,并仔细查阅你的实现文档以了解如何做到这一点。
【解决方案3】:

std::threadstd::mutex 都有一个 native_handle 方法,它允许您深入了解给定对象的平台实现。这告诉我,标准线程库旨在与平台实现配合得很好。

顺便说一句,std::threadstd::mutex 是做不同事情的不同对象,即。管理线程并提供跨线程同步。最后,内核完成了繁重的工作。

因此,如果您不担心可移植性,我不明白为什么这会是个问题。

顺便说一句,有时您可能需要本机平台实现,以便为您提供平台允许的更丰富的功能集。例如,BSD 线程允许不同类型的线程,一些线程库允许您设置新线程的堆栈大小。 C++ 线程 API 是可移植的最低公分母。

【讨论】:

  • 也许值得补充一点,线程和进程一样,是由内核在大多数/所有使用 pthread 的操作系统(通常可能是大多数操作系统)上实现的,这意味着 实际上只有无论您使用哪个用户空间库,系统级别的一种线程。对互斥锁不太确定,但如果我不得不猜测的话,我会说那里也是如此。
【解决方案4】:

如果您的问题是:我可以在一种互斥锁和另一种互斥锁之间随意切换吗?那么答案是否定的(除非所有底层都使用相同的实现,例如 pthread_mutex。)

但是,如果您要保护不同的资源组,则任何一组资源都可以通过任何一种实现来保护。实际上,有时使用信号量会更好(即信号量可用于定义一个写锁,多个读锁)。

因此,如果您要管理 4 组资源,您可以使用:

  • std::mutex,
  • pthread_mutex,
  • boost::mutex,
  • 信号量。

你不能做的是使用 boost::mutex 来访问受信号量保护的数据,反之亦然,或者使用 std::mutex 来使用受 pthread_mutex 保护的东西。

作为一个简单的例子,就代码而言,这意味着 getter 和 setter 将以这种方式完成:

void set(int new_value)
{
    guard lock(my_mutex);
    m_value = new_value;
}

int get() const
{
    guard lock(my_mutex);
    return m_value;
}

这两个函数使用相同的互斥体(此处为my_mutex),并且显然互斥体具有一个类型。

与此相反,您不能这样做:

void set(int new_value)
{
    guard lock(this_mutex_here);
    m_value = new_value;
}

int get() const
{
    SafeGuard lock(that_mutex_there);
    return m_value;
}

在第二个示例中,您使用了两个不同的互斥锁,这将无法按预期工作,因为set() 中的锁不会阻止get() 中的锁,反之亦然。所以它没有什么安全的(即使其中一名警卫被称为 SafeGuard。)

因此规则是,如果您使用名为 my_mutex 的互斥锁保护 m_value,则无论何时访问 m_value,您都必须锁定 my_mytex 互斥锁。您使用哪种实现并不重要,只要您在这种方式上保持一致即可。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-12
    • 1970-01-01
    • 2013-11-27
    • 2020-09-23
    • 1970-01-01
    • 2013-03-11
    • 2012-12-17
    相关资源
    最近更新 更多