假设我有一个C库,需要初始化和清除非线程安全的函数。具体来说,这些函数可能会调用其他库中的其他线程不安全函数。我不知道(在默认构建中)这些库将是什么。
现在考虑将Java绑定编写到此库的情况。 Java在运行任何Java代码之前会生成多个线程。更糟糕的是,在(例如)Eclipse插件的情况下,在我的代码接收控件时,可能有多个线程运行Java代码。其他一些线程可能正在使用上述不安全的函数。
我目前的计划是静态链接C库(在我的情况下,libcurl)和所有传递依赖 - 在我的情况下,一个TLS库(可能是mbedTLS)和(在Windows平台上) CRT。幸运的是,libcurl会清除它已分配的所有内容,因此不应出现与从一个堆分配并将其释放到另一个堆上相关的问题。因为所有内容都是静态链接的,并且不会尝试加载任何其他共享库,所以我可以从静态初始化程序初始化libcurl。
这甚至会起作用吗?还有更好的方法吗?
编辑:序列化库调用不起作用的原因,以及我认为我的解决方案可能有效的原因是全局状态不仅存储在libcurl本身,而且还存储在libcurl所依赖的库中。当我的代码加载时,其中一些库(例如OpenSSL)可能正在被其他代码使用。所以我需要锁定整个过程。
我认为隔离全局状态将工作的原因是libcurl(以及它所依赖的每个库)在初始化后是线程安全的。我需要确保libcurl的初始化不会创建竞争条件。之后我很好。
答案 0 :(得分:0)
[更新和修订]
您的担心似乎是您将对某些本机库(比如mbedTLS)进行直接和间接绑定,即本机库需要一次性初始化,这不是线程安全的,并且超出您的能力范围为了检测或控制,进程的不同线程可以同时尝试初始化该库,或者可能(不安全地)尝试多次初始化它。这当然似乎是最糟糕的情况。
另一方面,假设您可以成功构建一个包含所需本机库的单片,可动态加载的库以及所有依赖项(在内核之外)的传递闭包,以确保此库不与进程加载的任何其他库共享状态。您声明在非线程安全的初始化之后,组合堆栈将是线程安全的,至少在您打算使用它时。您想知道如何初始化库。
Java承诺每个类将由一个线程初始化,然后其初始化状态将对所有线程可见。 虽然这没有明确地解决问题,它肯定意味着如果您的本机库的初始化完全作为类的初始化执行 - 例如通过静态初始化程序,如您所建议的那样 - 那么正确的初始化状态将对所有Java线程都可见。这完全解决了我理解的问题。
我仍然怀疑构建整体库是必要,但是如果你真的必须处理最糟糕的情况,你似乎预料到那可能就是这样。但是,由于您无法将库与内核上的冲突需求隔离开来,因此可以想象策略不会足够。这将是图书馆依赖于您假设的共享状态的少数可以想象的充分理由之一,并且您的策略将阻碍该特定目的。我无法判断这种可能性是多么可能,但我怀疑它很可能。