我ctypes在python中使用模块来加载一个包含线程本地存储的共享c库.它是一个历史悠久的大型c库,我们正在努力使线程安全.该库包含许多全局变量和静态,因此我们对线程安全的初始策略是使用线程本地存储.我们希望我们的libarary与平台无关,并且在win32,win64和64位Ubuntu上编译和测试线程安全性.从纯粹的c-process开始,似乎没有任何问题.
但是在win32和Ubuntu的python(2.6和2.7)中,我们看到了内存泄漏.当python线程终止时,似乎没有正确释放线程本地存储.或者至少在某种程度上,python进程没有"意识到"内存被释放.实际上在win32上的ac#-program中也可以看到同样的问题,但是我们的win64服务器测试机器上也没有这个问题(也运行python 2.7).
这个问题可以用这样一个简单的玩具例子重现:
创建一个包含(linux/unix删除__declspec(dllexport))的c文件:
#include <stdio.h>
#include <stdlib.h>
void __declspec(dllexport) Leaker(int tid){
static __thread double leaky[1024];
static __thread int init=0;
if (!init){
printf("Thread %d initializing.", tid);
int i;
for (i=0;i<1024;i++) leaky[i]=i;
init=1;}
else
printf("This is thread: %d\n",tid);
return;}
Run Code Online (Sandbox Code Playgroud)
MINGW在Linux上的windows/gcc上编译机智如:
gcc -o leaky.dll(或leaky.so)-shared the_file.c
在Windows上,我们可以用Visual Studio编译,替换__thread为__declspec(thread).但是在win32上(我相信winXP),如果要在运行时加载库,这将不起作用LoadLibrary.
现在创建一个python程序,如:
import threading, ctypes, sys, time
NRUNS=1000
KEEP_ALIVE=5
REPEAT=2
lib=ctypes.cdll.LoadLibrary("leaky.dll")
lib.Leaker.argtypes=[ctypes.c_int]
lib.Leaker.restype=None
def UseLibrary(tid,repetitions):
for i …Run Code Online (Sandbox Code Playgroud) C++ 11有一些线程概念.例如,它定义了一个新的存储说明符thread_local,并为具有此存储说明符的变量指定"每个线程有一个不同的对象或引用"[basic.stc.thread].
什么被认为是为此目的的"线程"?是否只使用标准线程库创建的线程(即由std::thread对象表示的线程)?通过其他方式创建的线程怎么样(例如,直接在Linux上使用pthreads)?如果我使用提供用户空间线程的库,那么每个人都会获得自己的thread_local对象副本(我真的不知道如何实现)?
如果答案是"它的实现定义了什么被认为是用于诸如此类的目的的线程thread_local",那么有人可以举例说明一个众所周知的实现如何定义这个吗?
c++ multithreading language-lawyer thread-local-storage c++11
我读过Kerrisk的Linux编程接口:Linux和UNIX系统编程手册,第31章关于线程.本章包括线程特定数据(第31.3.4节)和线程本地存储(第31.4节).第663-669页介绍了这些主题.
线程特定数据(pthread_key_create,pthread_setspecific,pthread_getspecific,和朋友)看起来更加强大,但似乎多了几分使用麻烦,并显示使用内存管理器更频繁.
线程本地存储(__thread在静态和全局声明上)看起来不那么强大,因为它仅限于编译时间,但它似乎更容易使用,并且似乎在运行时不在内存管理器中.
关于运行时内存管理器我可能是错的,因为pthread_key_create在遇到__thread变量时可能会在幕后调用代码.
Kerrisk没有提供两种策略的比较/对比,他没有就何时使用哪种策略提出建议.
为问题添加上下文:我正在评估第三方库.库使用全局变量,也不能利用锁定了,我想在多线程程序中使用它.该程序使用线程来最小化网络延迟.
有没有赢家?或者有不同的情况需要使用其中一种吗?
我正在努力寻找简单的文档来说明其AsyncLocal<T>作用。
我写了一些测试,我认为这些测试告诉我答案是“是”,但如果有人能证实这一点那就太好了!(特别是因为我不知道如何编写对线程和延续上下文有明确控制的测试......所以它们可能只是巧合地工作!)
据我了解,ThreadLocal将保证如果您在不同的线程上,那么您将获得对象的不同实例。
ThreadLocal对象已经被使用过的线程)。await却不太愉快。您继续的线程(即使)不能保证与您开始的线程相同,因此您可能无法从另一端.ConfigureAwait(true)返回相同的对象。ThreadLocal相反,AsyncLocal 确实保证您将在调用的两侧获得相同的对象await。
但我找不到任何地方实际上说AsyncLocal将获得特定于初始线程的值,首先!
IE:
MyAsyncMethod),它在调用的任一侧引用其类中的“共享”AsyncLocal字段 ( ) 。myAsyncLocalawait我知道,对于 ,的每次单独调用MyAsyncMethod,myAsyncLocal.Value将在等待之前和之后返回相同的对象(假设没有任何内容重新分配它)
但是否能保证每次调用首先都会查看不同的对象?
正如一开始提到的,我创建了一个测试来尝试自己确定这一点。以下测试一致通过
public class AssessBehaviourOfAsyncLocal
{
private class StringHolder
{
public string HeldString { get; set; }
}
[Test, Repeat(10)]
public void RunInParallel()
{
var reps = Enumerable.Range(1, 100).ToArray();
Parallel.ForEach(reps, index => …Run Code Online (Sandbox Code Playgroud) C11引入了_Thread_local存储类说明符,可以static与extern存储类说明符结合使用,以将变量声明为线程本地.GNU C编译器套件实现了__thread具有相同语义的存储类说明符.
不幸的是我没有找到任何实际实现_Thread_local关键字的编译器(我尝试过gcc,clang和SUN studio).我目前使用以下构造来声明关键字thread_local:
/* gcc doesn't know _Thread_local from C11 yet */
#ifdef __GNUC__
# define thread_local __thread
#elif __STDC_VERSION__ >= 201112L
# define thread_local _Thread_local
#else
# error Don't know how to define thread_local
#endif
Run Code Online (Sandbox Code Playgroud)
我知道这可能不适用于MSVC和其他编译器.任何人都可以建议我一种更好的方法来声明thread_local它在尽可能多的编译器中工作吗?
Christoph建议Microsoft Visual C允许__declspec(thread).这是更新的宏定义:
/* gcc doesn't know _Thread_local from C11 yet */
#ifdef __GNUC__
# define thread_local __thread
#elif __STDC_VERSION__ >= 201112L
# define …Run Code Online (Sandbox Code Playgroud) 我想在TLS中存储日志记录上下文信息,以便我可以在入口点设置一个值,并在所有结果栈中提供该值.这项工作很好,但我也使用TPL和ThreadPool.然后问题就变成了如何将TLS数据迁移到其他线程.我自己可以做到这一切,但后来我失去了像Parallel.For这样的好方法.
使用TPL时是否有某种方法可以复制TLS?当它获得await功能时,这也将适用于C#.
谢谢,埃里克
.net asynchronous threadpool task-parallel-library thread-local-storage
我正在尝试使用Cython来并行化一个昂贵的操作,这涉及生成中间多维数组.
以下非常简化的代码说明了我正在尝试做的事情:
import numpy as np
cimport cython
cimport numpy as np
from cython.parallel cimport prange
from libc.stdlib cimport malloc, free
@cython.boundscheck(False)
@cython.wraparound(False)
def embarrasingly_parallel_example(char[:, :] A):
cdef unsigned int m = A.shape[0]
cdef unsigned int n = A.shape[1]
cdef np.ndarray[np.float64_t, ndim = 2] out = np.empty((m, m), np.float64)
cdef unsigned int ii, jj
cdef double[:, :] tmp
for ii in prange(m, nogil=True):
for jj in range(m):
# allocate a temporary array to hold the result of
# expensive_function_1
tmp_carray …Run Code Online (Sandbox Code Playgroud) python parallel-processing numpy cython thread-local-storage
我想在我的课程中做一些线程注册,所以我决定为该thread_local功能添加一个检查:
#include <iostream>
#include <thread>
class Foo {
public:
Foo() {
std::cout << "Foo()" << std::endl;
}
~Foo() {
std::cout << "~Foo()" << std::endl;
}
};
class Bar {
public:
Bar() {
std::cout << "Bar()" << std::endl;
//foo;
}
~Bar() {
std::cout << "~Bar()" << std::endl;
}
private:
static thread_local Foo foo;
};
thread_local Foo Bar::foo;
void worker() {
{
std::cout << "enter block" << std::endl;
Bar bar1;
Bar bar2;
std::cout << "exit block" << std::endl;
}
} …Run Code Online (Sandbox Code Playgroud) Windows中的内核模式驱动程序是否存在线程局部存储(TLS)等效(确切地说是Win32)?
我试图实现的目标:
最终,在我的驱动程序的调度程序中,它可能会调用许多其他函数(可能存在深度调用).我想提供一些特定于正在处理的请求的上下文信息.也就是说,我有一些结构,指针应该在所有被调用的函数中都可见,而不是将它作为参数显式传递给每个函数.
使用static/global不是一个完美的选择(多线程,同步对象等).
如果那是用户模式代码 - 在这种情况下显然会使用TLS.但是AFAIK没有像TlsGetValue/ 这样的内核模式功能TlsSetValue.这是有道理的 - 要使这些功能工作,必须首先分配一个进程范围的TLS索引.OTOH驱动程序代码可以在任意线程上调用,不限于特定进程.
但是,我实际上并不需要持久的特定于线程的存储.我只需要一个特定于线程的存储来进行顶级函数调用.
我想我知道如何以一种黑客的方式"实施"TLS.我将始终使用预定义的索引(例如,index = 0),而不是分配TLS索引.在顶级函数中,我将保存存储的TLS值,并用所需的值覆盖它.完成后,将恢复保存的值.
幸运的是我知道如何在Win32中实现TLS.TIB每个线程都有一个结构(线程信息块).在每个线程中,可以使用FS:[18h]选择器访问它.在TIB包含(除其他外)通过TLS使用的阵列.其余的非常简单.
但是,我更愿意使用官方API来实现类似的功能.
提前致谢.
PS One理论上可以使用SEH(也存储每线程信息).也就是说,包装顶级代码__try/__except,然后在需要上下文信息的地方 - 用一些参数引发可持续异常,在__except块中用上下文信息填充参数,然后恢复执行.这是一个100%有效的程序流程,不使用未记录的功能.但对我来说这似乎是一个丑陋的黑客,更不用说性能并发症了.
我有一个班级X:
class X { ... }
Run Code Online (Sandbox Code Playgroud)
我想做这个:
void f()
{
thread_local static X x = ...;
...
}
Run Code Online (Sandbox Code Playgroud)
(实际上我正在使用gcc所以关键字是"__thread")
但我不能,因为你只能有琐碎的thread_locals.
最好的解决办法是什么?
如果我这样做:
void f()
{
thread_local static X* p = 0;
if (!p)
p = new X(...);
X& x = *p;
...
}
Run Code Online (Sandbox Code Playgroud)
然后:
更新:
这是我到目前为止:
#include <iostream>
#include <type_traits>
using namespace std;
class X { public: X() { cout << "X::X()" << endl; }; ~X() { cout << "X::~X()" << endl; } };
void f()
{
static …Run Code Online (Sandbox Code Playgroud) c++ ×4
c ×2
c++11 ×2
python ×2
.net ×1
async-await ×1
asynchronous ×1
c# ×1
c11 ×1
ctypes ×1
cython ×1
gcc ×1
kernel ×1
memory-leaks ×1
numpy ×1
portability ×1
pthreads ×1
thread-local ×1
threadpool ×1
winapi ×1
windows ×1