我无法正确使用“交换”锁。考虑这种情况:
bool HidDevice::wait(const std::function<bool(const Info&)>& predicate)
{
/* A method scoped lock. */
std::unique_lock waitLock(this->waitMutex, std::defer_lock);
/* A scoped, general access, lock. */
{
std::lock_guard lock(this->mutex);
bool exitEarly = false;
/* do some checks... */
if (exitEarly)
return false;
/* Only one thread at a time can execute this method, however
other threads can execute other methods or abort this one. Thus,
general access mutex "this->mutex" should be unlocked (to allow threads
to call other methods) while at the same time, "this->waitMutex" should
be locked to prevent multiple executions of code below. */
waitLock.lock(); // How do I release "this->mutex" here?
}
/* do some stuff... */
/* The main problem is with this event based OS function. It can
only be called once with the data I provide, therefore I need to
have a 2 locks - one blocks multiple method calls (the usual stuff)
and "waitLock" makes sure that only one instance of "osBlockingFunction"
is ruinning at the time. Since this is a thread blocking function,
"this->mutex" must be unlocked at this point. */
bool result = osBlockingFunction(...);
/* In methods, such as "close", "this->waitMutex" and others are then used
to make sure that thread blocking methods have returned and I can safely
modify related data. */
/* do some more stuff... */
return result;
}
如何在不使代码过于复杂的情况下解决此“交换”问题?我可以在锁定另一个this->mutex
之前将其解锁,但是,恐怕在那一纳秒内,可能会发生竞争状况。
编辑:
想象一下,有3个线程正在调用wait
方法。第一个将锁定this->mutex
,然后锁定this->waitMutex
,然后解锁this->mutex
。第二个将锁定this->mutex
,并且必须等待this->waitMutex
可用。它不会解锁this->mutex
。第三个将卡在锁定this->mutex
上。
我想让最后2个线程等待this->waitMutex
可用。
编辑2:
使用osBlockingFunction
的示例。
答案 0 :(得分:3)
闻起来,设计/实现应该与enter code hereclass CenterView : View("My View") {
private val ExcelHandler: ExcelController by inject()
private var content = mutableListOf<Products>().observable()
private var rowcounter = SimpleIntegerProperty()
private var oktorun = SimpleBooleanProperty(true)
val table = TableView<Products>()
val data = SortedFilteredList(content).bindTo(table)
private var Accounts = mutableListOf<String>().observable()
override val root = borderpane() {
bottom{
hbox(10) {
style{
padding = box(10.px)
alignment = Pos.CENTER
}
button("Import"){
addClass(Styles.btmDesign)
style{
backgroundColor += Color.PURPLE
fontFamily = "Comic Sans MS"
}
useMaxWidth = true
enableWhen(oktorun)
action {
oktorun.value = false
runAsync {
ExcelHandler.readExcel("data/test.xlsx")
} ui { loadedText ->
content.isEmpty()
content.addAll(loadedText.observable())
rowcounter.value = loadedText.count()
Accounts.addAll(loadedText.map { it.Account }.toList().distinct()
.observable())
oktorun.value = true
}
}
}
hbox{
label("Rows ")
{
style{
fontSize = 20.px
fontWeight = FontWeight.BOLD
}
}
label {
style{
fontSize = 20.px
fontWeight = FontWeight.BOLD
textFill = Color.GREEN
}
bind(rowcounter)
}
}
textfield {
promptText = "Filter"
data.filterWhen(textProperty()) { query, item ->
item.Account!!.contains(query, ignoreCase = true)
}
}
}
left{
listview(Accounts) {
style{
padding = box(20.px)
fontSize = 20.px
fontWeight = FontWeight.BOLD
}
}
}
center{
style{
prefWidth = 100.px
alignment = Pos.CENTER
padding = box(20.px)
}
tableview(data) {
isEditable = true
style{
fontSize =20.px
fontWeight = FontWeight.EXTRA_BOLD
}
column("External", Products::ExternalProperty)
column("ItemRelation", Products::ItemRelationProperty)
column("Account",Products::AccountProperty)
column("Price", Products::AmmountProperty)
column("currency", Products::ValutaProperty)
column("Date", Products::DateProperty)
column("Status", Products::StatusProperty)
enableDirtyTracking()
columnResizePolicy = SmartResize.POLICY
}.multiSelect(true)
}
right {
}
}
}
}
上的std::condition_variable cv
有点不同,并且只有一个互斥体。当您编写“其他线程可以执行其他方法或中止该方法”时,将调用HidDevice::wait
来“中止”该等待。 cv.notify_one
{自动进入等待并解锁互斥锁},在cv.wait
{自动进入等待并锁定互斥锁}。像cv.notify
这样更简单:
HidDevice::wait
bool HidDevice::wait(const std::function<bool(const Info&)>& predicate)
{
std::unique_lock<std::mutex> lock(this->m_Mutex); // Only one mutex.
m_bEarlyExit = false;
this->cv.wait(lock, spurious wake-up check);
if (m_bEarlyExit) // A bool data-member for abort.
return;
/* do some stuff... */
}
上,线程等待直到某些逻辑成真。“中止”等待,将由另一个线程调用的其他/* do some checks... */
函数负责:
HidDevice
类似的东西。
答案 1 :(得分:0)
我建议创建一个小的“解锁”工具。这是具有反向语义的互斥包装。在lock
上unlocks
,反之亦然:
template <class Lock>
class unlocker
{
Lock& locked_;
public:
unlocker(Lock& lk) : locked_{lk} {}
void lock() {locked_.unlock();}
bool try_lock() {locked_.unlock(); return true;}
void unlock() {locked_.lock();}
};
现在代替:
waitLock.lock(); // How do I release "this->mutex" here?
您可以说:
unlocker temp{lock};
std::lock(waitLock, temp);
其中lock
是unique_lock
,而不是lock_guard
持有mutex
。
这将锁定waitLock
并解锁mutex
,就像通过一条不间断的指令一样。
现在,在对所有这些进行编码之后,我可以推断它可以转换为:
waitLock.lock();
lock.unlock(); // lock must be a unique_lock to do this
第一个版本是否或多或少可读性是一个观点问题。第一个版本更容易推论(一旦知道std::lock
会做什么)。但是第二个更简单。但是在第二篇中,读者必须更仔细地考虑正确性。
更新
只需阅读问题中的编辑内容即可。此解决方案无法解决编辑中的问题:第二个线程将阻止第三个(及后续线程)在需要mutex
但不需要waitMutex
的任何代码中取得进展,直到第一个线程释放{ {1}}。
因此,从这个意义上讲,我的回答在技术上是正确的,但不满足所需的性能特征。我将其留作参考。