C++ “新功能有什么优势?”;同步的;块,在C+中+;提供?
有一个新的实验特性(可能是C++20),即“同步块”。该块为代码段提供全局锁。下面是一个来自的示例C++ “新功能有什么优势?”;同步的;块,在C+中+;提供?,c++,multithreading,transactional-memory,C++,Multithreading,Transactional Memory,有一个新的实验特性(可能是C++20),即“同步块”。该块为代码段提供全局锁。下面是一个来自的示例 #包括 #包括 #包括 int f() { 静态int i=0; 同步的{ std::cout从表面上看,synchronized关键字在功能上类似于std::mutex,但通过引入新的关键字和相关语义(如包含同步区域的块),可以更容易地为事务性内存优化这些区域 特别是 STD::MutX 和朋友在原则上或多或少是编译器不透明的,而代码>同步< /COD>具有明确的语义。编译器不能确定标准库 ST
#包括
#包括
#包括
int f()
{
静态int i=0;
同步的{
std::cout从表面上看,synchronized
关键字在功能上类似于std::mutex
,但通过引入新的关键字和相关语义(如包含同步区域的块),可以更容易地为事务性内存优化这些区域
特别是 STD::MutX 和朋友在原则上或多或少是编译器不透明的,而<>代码>同步< /COD>具有明确的语义。编译器不能确定标准库<代码> STD::MutX < /C> >将很难将其转换为使用TM。C++编译器将工作正常。当std::mutex
的标准库实现发生更改,因此无法对该行为做出许多假设时,则为y
此外,如果块没有提供同步所需的显式作用域,编译器很难对块的范围进行推理-在简单的情况下,如单作用域的锁保护
,这似乎很容易,但在许多复杂的情况下,如锁逃逸了所需的函数编译器永远不知道在哪里可以解锁。锁通常不能很好地组合。请考虑:
//
// includes and using, omitted to simplify the example
//
void move_money_from(Cash amount, BankAccount &a, BankAccount &b) {
//
// suppose a mutex m within BankAccount, exposed as public
// for the sake of simplicity
//
lock_guard<mutex> lckA { a.m };
lock_guard<mutex> lckB { b.m };
// oversimplified transaction, obviously
if (a.withdraw(amount))
b.deposit(amount);
}
int main() {
BankAccount acc0{/* ... */};
BankAccount acc1{/* ... */};
thread th0 { [&] {
// ...
move_money_from(Cash{ 10'000 }, acc0, acc1);
// ...
} };
thread th1 { [&] {
// ...
move_money_from(Cash{ 5'000 }, acc1, acc0);
// ...
} };
// ...
th0.join();
th1.join();
}
…无论交易是否作为一个整体进行,都可以从中受益
总之,在不使用互斥锁的情况下,不会给BankAccount造成负担,也不会因为来自用户代码的请求冲突而出现死锁风险。不确定是否确实如此,但cppreference使第一个版本听起来像是保证按顺序打印,而AFAIK第二个版本则没有。“尽管同步块的执行就像在全局锁下一样,但实现需要检查每个块中的代码,并对事务安全代码使用乐观并发(在可用的情况下由硬件事务内存备份),而对非事务安全代码使用最小锁。"“量子物理”,“代码> STD::CuxIGueGue和 STD::MutX < /C>不是C++语言的一部分:它们只是库中定义的类。特别是编译器无法知道什么是<代码>互斥< <代码>意味着互斥操作与操作系统交互,或者它们对线程有什么影响。onized
关键字在这方面会有很大的不同。不,优化不能移除显式锁;锁有明显的副作用。我明白了。感谢您的解释。请在SO平台上提供答案。
std::mutex m;
int f()
{
static int i = 0;
std::lock_guard<std::mutex> lg(m);
std::cout << i << " -> ";
++i;
std::cout << i << '\n';
return i;
}
//
// includes and using, omitted to simplify the example
//
void move_money_from(Cash amount, BankAccount &a, BankAccount &b) {
//
// suppose a mutex m within BankAccount, exposed as public
// for the sake of simplicity
//
lock_guard<mutex> lckA { a.m };
lock_guard<mutex> lckB { b.m };
// oversimplified transaction, obviously
if (a.withdraw(amount))
b.deposit(amount);
}
int main() {
BankAccount acc0{/* ... */};
BankAccount acc1{/* ... */};
thread th0 { [&] {
// ...
move_money_from(Cash{ 10'000 }, acc0, acc1);
// ...
} };
thread th1 { [&] {
// ...
move_money_from(Cash{ 5'000 }, acc1, acc0);
// ...
} };
// ...
th0.join();
th1.join();
}
void move_money_from(Cash amount, BankAccount &a, BankAccount &b) {
synchronized {
// oversimplified transaction, obviously
if (a.withdraw(amount))
b.deposit(amount);
}
}