我们正在开发一个带有 C 接口(interface)的 C++ 库。在C接口(interface)中,有:
- 初始化库的函数(
Init()
- 构造使用给定参数实现功能的对象); - 取消初始化库的函数(
DeInit()
- 销毁该对象),以及; - 几个仅调用对象上相应方法的函数(例如
Foo()
和Bar()
)。
类本身是线程安全的,但我希望 C 接口(interface)(即 Init()
、 DeInit()
、 Foo()
和 Bar()
)也是线程安全的。
有一个全局变量——指向类实例的指针。您认为以下哪种方法最好?你会用不同的方式来做吗?
- 有一个全局
unique_ptr<T>
以及全局读/写锁。Foo()
和Bar()
锁定以供阅读;Init()
和DeInit()
锁定它以便写入。 - 使用信号量来跟踪使用实例的线程数。如果
DeInit()
被调用时,等待信号量直到其计数为 0。 - 使用
shared_ptr
语义。全局shared_ptr
可以更改,但对象不会被删除,直到没有用户为止。这有可能使系统过载,因为可能有多个实例(消耗大量内存)来满足挂起操作的需求,因为 Init() 不会(也不需要)等到挂起操作完成.
选项 3 似乎最容易使用 C++11 实现。如果我错了或太模糊,请纠正我。
编辑 说明:对 Init() 和 DeInit() 的调用正在更改全局指针,因此应通过锁来防止它们同时运行。 Foo() 和 Bar() 应该能够同时运行。
编辑澄清 通过 C 接口(interface),我指的是实现 C 接口(interface)的函数集。我希望这组函数是线程安全的。
最佳答案
通常,如果可能的话,应该避免使用全局变量,即使是隐藏变量。由于您的类已经是线程安全的,因此可以通过将句柄返回给用户来完全消除锁定。他们最有资格知道该怎么做。然后编写好的文档并让用户决定同步什么以及如何同步。例如:
void *handle = Init(...);
void *value = Foo(handle, ...);
int status = Bar(handle, ...);
DeInit(handle, ...);
如果库用户代码是用 C++ 编写的,那么将其包装到具有同步访问(如果需要)的 C++ 智能处理程序类中是很简单的。如果用户以某种方式知道永远不会发生并发访问(例如,用户代码可能在单个线程中运行),则无需锁定任何内容。
[编辑:错别字]
关于c++ - C++多线程设置中服务器重新初始化的良好设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18400172/