multithreading - 使用依赖注入(inject)时如何使共享资源线程安全?

标签 multithreading coldfusion dependency-injection thread-safety locking

我当前的应用程序使用对象的单个实例作为许多主要组件的全局变量,据我所知,这不如使用依赖注入(inject)。

我希望将来让我的应用程序开源,但首先我想重构代码以使用最推荐的团队协作技术,以便其他开发人员能够更轻松地更改我的源代码。

共享资源示例:在 CFML 语言中,您有服务器作用域,它是可用于整个服务器实例的任何请求的共享内存。

这是我管理服务器范围变更的新设计理念:

  1. 创建名为 ServerMemoryManager 的组件的单个实例,它提供用于写入和读取服务器范围的接口(interface)。
  2. 任何其他需要访问服务器范围的代码都将通过 init() 函数或 setServerMemoryManager() 函数注入(inject)对 ServerMemoryManager 单个实例的引用。
  3. 每当组件读取/写入数据到 ServerMemoryManager 对象时,它将能够在内部锁定服务器范围,这样就没有 2 个线程可以同时写入服务器范围内的同一 block 内存。

这是管理需要锁定以实现线程安全的共享资源(共享内存、文件系统等)的最佳方式吗?

请描述可用于管理在某些被认为是最佳实践的某些读/写操作期间需要锁定的共享资源的任何其他方法。

编辑:基于已接受的答案,我将使用命名锁而不是锁定 scope="server",并使用更细粒度的锁定来管理共享资源。这可能允许使用多个对象来管理共享资源,假设它们都管理共享内存中的不同 key 或文件系统中的文件。例如,一个应用程序可以有自己的唯一键或分配给它的目录,这样它就不会与另一个试图更改共享资源的应用程序发生冲突。

Edit2:我发现如果我在创建对象时将范围传递给 init 函数,我可以为每个范围使用一个名为 scope.cfc 的组件。我现在正在使用细粒度的命名锁。让我知道是否可以改进。实际修改后的代码现在看起来像这样(我排除了读取、删除、清除的代码)。似乎也不再需要 scope.cfc 组件的单个实例。

            <cfcomponent>
                <cfscript>
                variables.scope=false;
                variables.scopeName=false;
                </cfscript>
                <cffunction name="init" access="public" output="no" returntype="scope">
                    <cfargument name="scope" type="struct" required="yes">
                    <cfargument name="scopeName" type="string" required="yes">
                    <cfscript>
                    variables.scope=arguments.scope;
                    variables.scopeName=arguments.scopeName;
                    return this;
                    </cfscript>
                </cffunction>
                <cffunction name="write" access="public" output="no" returntype="boolean">
                    <cfargument name="key" type="string" required="yes">
                    <cfargument name="value" type="any" requires="yes">
                    <cfargument name="timeout" type="numeric" required="no" default="10">
                    <cftry>
                        <cflock type="exclusive" name="zcore-#variables.scopeName#-scope-#arguments.key#" timeout="#arguments.timeout#" throwontimeout="yes">
                            <cfscript>
                            variables.scope[arguments.key]=arguments.value;
                            </cfscript>
                        </cflock>
                        <cfcatch type="lock"><cfreturn false></cfcatch>
                    </cftry>
                    <cfreturn true>
                </cffunction>
            </cfcomponent>

** Edit3:** 我测试了通过这样的组件方法从服务器范围读取的性能,发现它比使用只读锁直接读取服务器范围慢 20 倍,而没有使用只读锁慢 4 倍锁。每个请求数百或数千次额外函数调用的开销太慢了。在 Railo 3.3.x 上完成的测试。

我更喜欢在非公共(public)请求中构建一个大对象,然后设置一个共享内存作用域键,然后尝试将一个不完整的对象写入作用域。示例:

<cfscript>
ts=structnew();
ts.largeObject=buildLargeObject();
server.cachedObject=ts;
</cfscript>

当您只将完整的对象写入共享内存时,这可以让您避免锁定整个应用程序,因为更新单个结构键是线程安全的。但是,当您在启动时构建大对象时,您需要确保在完全创建该对象之前将其锁定。

我将通过在 init 函数中使用 this 范围而不是变量范围来使范围变量变得直接可读,以避免降低应用程序的速度。

最佳答案

CFLOCK 仅在每次出现都以相同方式锁定时才阻止代码执行。

例如:

page1.cfm

<cflock type="exclusive" scope="server" timeout="10" >
   <cfset application.xyz = 'abc'>
</cflock>

page2.cfm

<cfset application.xyz = '123'>

如果 page2 与 page1 同时运行,Page2.cfm 将取消对 page1.cfm 的所有锁定。也就是说,最好在 cfc 内部进行锁定,这样就不必锁定每个对象。

但是,锁定每次出现是不够的。以下内容也没什么用。

page1.cfm

<cflock type="exclusive" scope="server" timeout="10" >
   <cfset application.xyz = 'abc'>
</cflock>

page2.cfm

<cflock type="exclusive" scope="server" timeout="10" >
   <cfset application.xyz = '123'>
</cflock>

这将停止对 page1 和 page2 的每个请求的处理,但不会保护 page1 上的 application.xyz 免受对 page2 上的 application.xyz 所做的更改。为此,您需要 give your locks a "name" .

Locks name. Mutually exclusive with the scope attribute. Only one request can execute the code within a cflocktag with a given name at a time. Cannot be an empty string.

Permits synchronizing access to resources from different parts of an application. Lock names are global to a ColdFusion server. They are shared among applications and user sessions, but not clustered servers.

因为您正在创建对象的多个实例,所以我相信 serverMemoryManagerObject 可能会干扰 serverMemoryManagerObject2,除非您为锁命名。

这里有一些关于锁定注意事项的更多信息

关于multithreading - 使用依赖注入(inject)时如何使共享资源线程安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13190209/

相关文章:

validation - 检查变量名是否有效的函数

ColdFusion 循环条件属性

android - 从 Kotlin 中的构造函数注入(inject) Koin

c++ - std::mutex 的线程安全

c# - 为什么空白线程要占用 30% 的 CPU?

mysql - 例程 [procedurename] 的存储过程错误 OUT 或 INOUT 参数 1 不是 BEFORE 触发器中的变量或 NEW 伪变量

c# - 如何在 .Net 核心控制台应用程序中使用依赖注入(inject)

java - 多个线程可以同时等待一个对象吗?

c++ - 空指针检查线程安全

wcf - 服务契约(Contract) WCF 中的 DI