我想使用 Kotlin Coroutines 实现一个简单的线程安全 Buffer,因为项目中已经使用了协程。
缓冲区将在多线程和单线程上下文中使用,因此使用 suspend fun getMostRecentData()
似乎不太合理(请参见下面的代码)。
这就是我目前所拥有的。事实上,我必须编写所有代码来锁定互斥锁,这让我想知道我是否做错了什么。
无论如何,这是代码:
class SafeBuffer(
private val dispatcher: CoroutineDispatcher,
private val bufferSize: Int
) {
private val buffer = LinkedList<MyDataType>()
private val mutex = Mutex()
val size: Int
get() = buffer.size
// First approach: make a suspend fun
// Not great because I will need a runBlocking{} statement somewhere, every time I want to access the buffer
suspend fun getMostRecentData() : MyDataType? {
mutex.withLock {
return if (buffer.isEmpty()) null else buffer.last
}
}
// Second approach: use a runBlocking block inside the function
// Seems like it is missing the purpose of coroutines, and I'm not
// sure it is actually thread safe if other context is used somehow?
fun getMostRecentData() : MyDataType? {
runBlocking(dispatcher) {
mutex.withLock {
return if (buffer.isEmpty()) null else buffer.last
}
}
}
/**** More code ****/
(...)
}
那么实现这一目标的最惯用/最优雅的方式是什么?
最佳答案
扩展我的评论,我认为让缓冲区类只公开一个suspend fun
是惯用的,因为类的使用者将负责弄清楚他们想如何使用它(通过 runBlocking
或来自另一个协程)。如果您发现此用例经常出现,惯用的方法可能是在 SafeBuffer
上添加一个扩展函数来提供此功能。
扩展函数在协程 API 中随处可见。在您的代码示例中,甚至 Mutex.withLock
也被定义为扩展函数。
class SafeBuffer(...) {
private val buffer = LinkedList<MyDataType>()
private val mutex = Mutex()
suspend fun getMostRecentData() : MyDataType? =
mutex.withLock {
if (buffer.isEmpty()) null else buffer.last
}
}
fun SafeBuffer.getMostRecentDataBlocking(): MyDataType? =
runBlocking {
getMostRecentData()
}
关于kotlin - 在 Kotlin 中锁定互斥锁的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67321436/