5

我不确定 pthread dataspecific 是如何工作的:考虑到下一个代码(在网上找到),这是否意味着我可以在主线程中创建例如 5 个线程,只在其中一些线程中调用 func(比如说 2 ) 这些线程会将数据“键”设置为某个值 (ptr = malloc(OBJECT_SIZE) ),而其他线程将具有相同的键,但具有 NULL 值?

static pthread_key_t key;
static pthread_once_t key_once = PTHREAD_ONCE_INIT;

static void
make_key()
{
  (void) pthread_key_create(&key, NULL);
}

func()
{
  void *ptr;

  (void) pthread_once(&key_once, make_key);
  if ((ptr = pthread_getspecific(key)) == NULL) {
    ptr = malloc(OBJECT_SIZE);
    ...
    (void) pthread_setspecific(key, ptr);
  }
  ...
}

关于数据特定的工作原理以及它如何在 pthread 中实现(简单方式)的一些解释将不胜感激!

4

2 回答 2

7

你的推理是正确的。这些调用是针对特定于线程的数据。它们是给每个线程一个“全局”区域的一种方式,它可以在其中存储它需要的东西,但前提是它需要它。

密钥在所有线程之间共享,因为它是在pthread_once()第一次需要它时创建的,但是每个线程赋予该密钥的值是不同的(除非它仍然设置为 NULL)。通过将值 avoid*分配给内存块,需要线程特定数据的线程可以分配它并保存地址以供以后使用。并且不调用需要线程特定数据的例程的线程永远不会浪费内存,因为它从未分配给它们。

我使用它们的一个领域是使标准 C 库线程安全。我参与的一个实现中的strtok()函数(与我们这样做时被认为是可憎的线程安全相反strtok_r())在第一次调用它时使用了几乎完全相同的代码,以分配一些将被使用的内存strtok()用于存储后续调用的信息。这些后续调用将检索特定于线程的数据以继续标记字符串,而不会干扰其他线程执行完全相同的操作。

这意味着该库的用户不必担心线程之间的串扰——他们仍然必须确保单个线程在最后一个线程完成之前不会调用该函数,但这与单线程代码相同。

它允许我们为系统中运行的每个线程提供一个“适当的”C 环境,而没有其他供应商对其用户施加的通常的“您必须调用这些特殊的非标准重入例程”限制。

至于实现,根据我对 DCE 用户模式线程(我认为是当前 pthread 的前身)的记忆,每个线程都有一个单独的结构,用于存储指令指针、堆栈指针、寄存器内容等内容。向这个结构添加一个指针以以最低的成本实现非常强大的功能是一件非常简单的事情。指针指向键/指针对的数组(在某些实现中为链表),因此每个线程可以有多个键(例如,一个用于strtok(),一个用于rand())。

于 2009-02-14T12:38:37.267 回答
1

你的第一个问题的答案是肯定的。简单来说,它允许每个线程分配和保存自己的数据。这大致相当于没有每个线程简单地分配和传递它自己的数据结构。API 省去了将线程局部结构传递给所有子函数的麻烦,并允许您按需查找它。

只要结果相同,实现实际上并不重要(它可能因操作系统而异)。

您可以将其视为两级哈希图。键指定您要访问的线程本地“变量”,第二级可能会执行线程 ID 查找以请求每个线程的值。

于 2009-02-14T14:05:57.337 回答