线程参数的高效快捷方式

使用参数创建线程的最有效方法是什么? 参数是一个结构,如果结构不能保留在父线程堆栈上,则有两种解决方案。

具有动态内存分配

struct Arg{ int x; int y; }; void* my_thread(void* v_arg){ Arg* arg = (Arg*) v_arg; //... running delete arg; return NULL; } //Creating a thread void a_function(){ Arg* arg = new Arg; arg->x = 1; arg->y = 2; pthread_t t; pthread_create(&t, NULL, my_thread, arg); pthread_detach(t); } 

用信号量

 struct Arg{ sem_t sem; int x; int y; }; void* my_thread(void* v_arg){ Arg* arg = (Arg*) v_arg; int arg_x = v_arg->x; int arg_y = v_arg->y; sem_post( &(v_arg->sem) ); //... running return NULL; } //Creating a thread void a_function(){ Arg arg; arg.x = 1; arg.y = 2; sem_init( &(arg.sem), 0, 0); pthread_t t; pthread_create(&t, NULL, my_thread, &arg); pthread_detach(t); sem_wait( &(arg.sem) ); sem_destroy( &(arg.sem) ); } 

我使用Linux和Windows。

在您发布的代码中,最有效的实现是使用堆分配(您的第一个示例)。 原因是堆分配(使用new()或malloc)比上下文切换便宜得多。 考虑在第二个例子中需要发生什么:

  1. 为Arg分配堆栈空间
  2. 初始化semphore
  3. 启动线程并切换上下文
  4. 将变量复制到新堆栈
  5. 切换上下文
  6. 消灭信号量
  7. 分离线程
  8. 切换上下文

或者,你的第一个例子:

  1. 为Arg分配堆空间
  2. 启动线程
  3. 分离线程
  4. 切换上下文

这取决于。 如果您的结构不大,最好动态分配它以最小化奇数同步调用。 否则,如果您的结构非常大并且您为具有少量内存的系统编写代码,则最好使用信号量(甚至是condvar)。

primefaces操作解决方案。 这是为你的参数获取内存的一种非常高速的方法。

如果参数总是相同的大小,则预先分配一堆参数。 将pNext添加到结构中以将它们链接在一起。 使用pNext创建一个_pRecycle全局,将所有可用的全局链接为链接列表。 当你需要一个参数时,在垃圾邮件列表的头部使用primefaces操作来CAS。 完成后,使用primefaces操作将arg放回垃圾列表的开头。

CAS指的是像__sync_bool_compare_and_swap这样的东西,它在成功时返回1。

抓住参数记忆:

 while (1) { // concurrency loop pArg = _pRecycle; // _pRecycle is the global ptr to the head of the available arguments // POINT A if (CAS(&_pRecycle, pArg->pNext, pArg)) // change pRecycle to next item if pRecycle hasn't changed. break; // success // POINT B } // you can now use pArg to pass arguments 

完成时回收参数内存:

 while (1) { // concurrency loop pArg->pNext = _pRecycle; if (CAS(&_pRecycle, pArg, pArg->pNext)) // change _pRecycle to pArg if _pRecycle hasn't changed. break; // success } // you have given the mem back 

如果某些东西使用并且循环使用pArg而另一个线程在A点和B点之间被换出,则存在竞争条件。如果您的工作需要很长时间来处理,这将不是问题。 否则你需要对列表的头部进行版本化…要做到这一点,你需要能够一次primefaces地改变两件事…… Unions结合64位CAS来拯救!

 typedef union _RecycleList { struct { int iversion; TArg *pHead; } unsigned long n64; // this value is iVersion and pHead at the same time! } TRecycleList; TRecycleList _Recycle; 

得到记忆:

 while (1) // concurrency loop { TRecycleList Old.n64 = _Recycle.n64; TRecycleList New.n64 = Old.n64; New.iVersion++; pArg = New.pHead; New.pHead = New.pHead->pNext; if (CAS(&_Recycle.n64, New.n64, Old.n64)) // if version isnt changed we get mem break; // success } 

把回忆放回去:

 while (1) // concurrency loop { TRecycleList Old.n64 = _Recycle.n64; TRecycleList New.n64 = Old.n64; New.iVersion++; pArg->pNext = New.pHead; New.pHead = pArg; if (CAS(&_Recycle.n64, New.n64, Old.n64)) // if version isnt changed we release mem break; // success } 

由于99.9999999%的时间没有两个线程同时执行代码来获取内存,因此您可以获得出色的性能。 我们的测试表明,CAS只需设置_pRecycle = pRecycle-> pNext,速度只有2倍。 64位和128位CAS与32位一样快。 基本上它尖叫。 当两个线程实际竞争时,并发循环每隔一段时间执行两次。 一个人总是会赢,所以比赛解决得非常快。