如何在多线程上下文中初始化静态变量?
我想到了在函数内使用 static 关键字的一个好方法,如下所示:
void threadSafeWrite(int *array, int writeIndex, int writeData){
static void *threadLock = Lock_create(); //in my code locks are void* to be cross-platform compatable
Lock_aquire(threadLock);
array[writeIndex] = writeData;
Lock_release(threadLock);
}
简而言之,这似乎是创建关键部分的好方法。我的问题是,如何以线程安全的方式初始化 threadLock?我担心这个例子的问题是锁将被分配多次,并且每个线程将使用不同的锁。关于如何解决这个问题有什么想法吗?看来是先有鸡还是先有蛋的问题。我想要一个可以同时使用 pthread 和 windows 线程的解决方案(或多个解决方案)。
编辑:我想要此功能的原因是因为它提供了一种非侵入式方法来测试单线程或多线程运行一段代码(用于调试目的)时是否存在差异。
I thought up a good use of the static keyword inside a function to be something like this:
void threadSafeWrite(int *array, int writeIndex, int writeData){
static void *threadLock = Lock_create(); //in my code locks are void* to be cross-platform compatable
Lock_aquire(threadLock);
array[writeIndex] = writeData;
Lock_release(threadLock);
}
In short it seems like a good way to make a critical section. My question is though, how do I initialize the threadLock in a threadsafe manner? The problem with the example I fear is that the lock will get allocated multiple times and each thread will use a different lock. Any ideas on how to fix this? Seems like a chicken and egg problem. I want a solution (or solutions) which work with both pthreads and windows threads.
EDIT: the reason I want this functionality is because it provides a non-intrusive way to test whether there is a difference when running a piece of code single-threaded or multithreaded (meant for debug purposes).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
一种方法是使用全局锁来序列化初始化路径。然而,您需要一个 SMP 内存屏障上的便携式包装器;锁隐含的获取屏障不够,因为原则上它允许编译器和/或CPU 缓存获取锁之前的内存读取结果。这是一个例子:
也就是说,我建议将锁与数据一起放置,而不是与作用于数据的函数一起放置。毕竟,您打算如何同步这样的读者呢?如果以后想对单独的数组使用单独的锁怎么办?如果您想编写其他函数来稍后获取该锁怎么办?
One approach is to use a global lock to serialize the initialization paths. You'll need a portable wrapper over a SMP memory barrier however; the acquire barrier implied by the lock is not sufficient, as it, in principle, allows the compiler and/or CPU to cache the results of memory reads from before the lock acquisition. Here's an example:
That said, I would recommend putting the locks with the data, not with the functions that act on the data. After all, how do you intend to synchronize readers like this? What if you want to use separate locks for separate arrays later? And what if you want to write other functions that take that lock later down the road?
不起作用,因为静态变量的初始值设定项必须是 C 中的常量。函数调用不是常量。这与 C++ 不同,在 C++ 中,您可以在输入
main
之前让static
执行工作。例如,这不会编译:最简单的选择是使锁成为全局锁并在进入 MT 模式之前初始化它们。更好的选择是将它们与它们所保护的数据一起传递。
PS:我建议不要使用
void *
来获取不透明的指针。相反,应实现特定于平台的单元素struct Lock
以确保类型安全。Won't work because the initializer of a
static
variable must be a constant in C. A function call is not a constant. This is different from C++, where you can make astatic
perform work beforemain
is entered. For example, this won't compile:The simplest option is to make your locks global and initialize them before going into MT mode. A better option is to pass them along with the data they guard.
P.S.: I advise against using a
void *
to get an opaque pointer. Instead, implement a platform-specific, one-elementstruct Lock
for type-safety.Lock_create
函数的整个想法被打破了;创建它的行为需要同步,但您无法保证同步,因为您还没有锁!不要使用指针作为锁。相反,创建一个结构并将该结构的地址传递给锁定和解锁函数。或者更好的是,使用操作系统提供的那些,因为没有办法在普通 C 中实现锁定自己。此外,每个说您需要使锁成为“全局”的人都是错误的。只要它是您拥有的静态存储持续时间,函数级别范围就可以。您只需要消除分配函数
Lock_create
并为锁使用适当的类型。The whole idea of a
Lock_create
function is broken; the act of creating it would require synchronization, which you can't guarantee because you don't have a lock yet! Don't use pointers for locks. Instead create a struct and pass the address of that struct to your locking and unlocking functions. Or better yet, use the ones provided by your OS, since there's no way to implement locking yourself in plain C.Also everyone who's said you need to make the lock "global" is wrong. Function level scope is fine as long as it's static storage duration, which you have. You just need to eliminate the allocation function
Lock_create
and use an appropriate type for the lock.有多种选择:
使用不涉及调用任何函数的锁的静态初始化。例如,使用pthreads
There are various options:
pthread_once()
or equivalent, which will ensure the initialization code is called once and all subsequent callers see its effects.Use a static initialization of the lock that does not involve calling any function. For example, using pthreads