C语言线程对象和线程存储的实现

 更新时间:2021年03月09日 11:28:10   投稿:zx  
这篇文章主要介绍了C语言线程对象和线程存储的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

当每个线程为各自的变量使用全局标识符时,为保留这些变量各自的数据,可以采用线程对象(thread-local object)和线程存储(thread-specific storage)。

这两项技术允许在一个给定线程中执行的函数可以共享数据而不造成冲突,即便当其他线程也在执行同样函数的情况下。

使用线程对象

线程对象是在声明中包含新存储类修饰符 _Thread_local 的全局或静态对象。这意味着:每一个线程拥有属于自己的线程对象实例,它在线程启动时创建并初始化。对象的存储周期等于线程的运行时间。在一个线程内表达式里面的线程对象名,将引用这个对象在当前线程下的本地实例。

修饰符 _Thread_local 可以与修饰符 static 或 extern 同时使用。头文件 threads.h 定义了 thread_local 作为 _Thread_local 的同义词。在例 1 中,主线程和新启动线程各自拥有线程本地变量 var 的一个实例。

【例1】使用一个线程对象

#include <stdio.h>
#include <threads.h>
thread_local int var = 10;
void print_var(void){ printf("var = %d\n", var); }
int func(void *);        // 线程函数
int main(int argc, char *argv[])
{
  thrd_t th1;
  if ( thrd_create( &th1, func, NULL ) != thrd_success ){
   fprintf(stderr,"Error creating thread.\n"); return 0xff;
  }
  print_var();        // 输出:var = 10
  thrd_join(th1, NULL);
  return 0;
}
int func(void *arg)       // 线程函数
{
  var += 10;         // 线程本地变量
  print_var();        // 输出:var = 20
  return 0
}

使用线程存储

线程存储技术要比线程对象更加灵活。例如,独立线程可以使用不同大小的内存。它们可以动态地分配内存,并通过调用析构函数再次释放内存。同时,可以使用相同的标识符访问这些独立线程所在的不同内存区域。

这种灵活性通过初始创建一个全局的键(key)实现,该键表示了一个指向线程存储的指针。然后,独立线程通过指定其线程存储的位置加载这个指针。该全局键值是类型为 tss_t 的对象。头文件 threads.h 包含了该类型的定义以及 4 个用于管理线程存储(简称 TSS)函数的声明:

int tss_create(tss_t*key,tss_dtor_t dtor);

通过析构函数 dtor 生成一个新的 TSS 指针,并且将 key 引用的对象设置为唯一标识该 TSS 指针的值。类型 tss_dtor_t 是一个函数指针,定义为 void(*)(void*)(它指的是一个函数指针,该函数参数为 void 指针,并且该函数没有返回值)。dtor 的返回值可以是一个空指针。

void tss_delete(tss_t key);

释放 TSS 键 key 所使用的所有资源。

int tss_set(tss_t key,void*val);

对于调用 tss_set()的线程,将 key 所标识的 TSS 指针设置为 val 所引用的内存地址。

void*tss_get(tss_t key);

返回指向内存块的指针,该内存块为正在调用的线程通过函数 tss_set()设置。如果发生错误,tss_get()返回 NULL。

如果函数 tss_create()和 tss_set()发生错误,则返回 thrd_error;否则,返回 thrd_success。

例 2 中的程序在动态分配的线程存储中,保留线程的名称。

【例2】使用线程存储

#include <threads.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
tss_t key;               // 用于TSS指针的全局键
int thFunc(void *arg);     // 线程函数
void destructor(void *data);  // 析构函数
int main(void)
{
  thrd_t th1, th2;
  int result1 = 0, result2 = 0;
  // 创建一个TSS密钥
  if (tss_create(&key, destructor) != thrd_success)
   return -1;
  // 创建线程
  if (thrd_create(&th1, thFunc, "Thread_1") != thrd_success
     || thrd_create(&th2, thFunc, "Thread_2") != thrd_success)
    return -2;
  thrd_join(th1, &result1); thrd_join(th2, &result2);
  if ( result1 != 0 || result2 != 0 )
    fputs("Thread error\n", stderr);
  else
    puts("Threads finished without error.");
  tss_delete(key);      // 释放TSS指针所有的资源
  return 0;
}
void print(void)        // 显示线程存储
{
 printf( "print: %s\n", (char*)tss_get(key) );
}
int thFunc( void *arg )
{
  char *name = (char*)arg;
  size_t size = strlen(name)+1;
  // 设置线程存储
  if ( tss_set(key, malloc(size)) != thrd_success )
   return -1;
  // 存储数据
  strcpy((char*)tss_get(key), name);
  print();
  return 0;
}
void destructor(void *data)
{
 printf("Destructor for %s\n", (char*)data);
 free(data);      // 释放内存
}

到此这篇关于C语言线程对象和线程存储的实现的文章就介绍到这了,更多相关C语言线程对象和线程存储内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Qt实现TCP同步与异步读写消息的示例代码

    Qt实现TCP同步与异步读写消息的示例代码

    这篇文章主要为大家详细介绍了如何在 Qt 中实现 TCP 客户端和服务器的同步和异步读写消息,有需要的小伙伴可以跟随小编一起学习一下
    2024-04-04
  • C语言结构体成员赋值的深拷贝与浅拷贝详解

    C语言结构体成员赋值的深拷贝与浅拷贝详解

    C语言中的浅拷贝是指在拷贝过程中,对于指针型成员变量只拷贝指针本身,而不拷贝指针所指向的目标,它按字节复制的。深拷贝除了拷贝其成员本身的值之外,还拷贝成员指向的动态内存区域内容。本文将通过示例和大家详细说说C语言的深拷贝与浅拷贝,希望对你有所帮助
    2022-09-09
  • C++实现简单的HTTP服务器

    C++实现简单的HTTP服务器

    这篇文章主要为大家详细介绍了C++实现简单的HTTP服务器的相关资料,感兴趣的朋友可以参考下
    2016-05-05
  • Qt实现可拖动按钮

    Qt实现可拖动按钮

    这篇文章主要为大家详细介绍了Qt实现可拖动按钮,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-08-08
  • 基于C++实现去除字符串头尾指定字符功能

    基于C++实现去除字符串头尾指定字符功能

    编程时我们经常需要对字符串进行操作,其中有一项操作就是去除字符串的头(尾)指定的字符,比如空格。本文为大家详细介绍了如何利用C++实现这一效果,需要的可以参考一下
    2022-04-04
  • C/C++ 多线程的学习心得总结

    C/C++ 多线程的学习心得总结

    本篇文章是对C/C++中多线程的学习心得总结进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C语言中access/_access函数的使用实例详解

    C语言中access/_access函数的使用实例详解

    本文通过实例代码给大家介绍了C语言中access/_access函数的使用,代码简单易懂,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-09-09
  • C++精要分析lambda表达式的使用

    C++精要分析lambda表达式的使用

    Lambda表达式是现代C++在C ++ 11和更高版本中的一个新的语法糖 ,在C++11、C++14、C++17和C++20中Lambda表达的内容还在不断更新。 lambda表达式(也称为lambda函数)是在调用或作为函数参数传递的位置处定义匿名函数对象的便捷方法
    2022-05-05
  • 深度解析C语言中数据的存储

    深度解析C语言中数据的存储

    本文详细介绍了C语言中数据的存储,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-05-05
  • C++中I/O模型之select模型实例

    C++中I/O模型之select模型实例

    这篇文章主要介绍了C++中I/O模型的select模型,实例讲述了I/O模型的用法,具有一定的参考借鉴价值,需要的朋友可以参考下
    2014-10-10

最新评论