我有两个用例.
答:我想将两个线程的访问同步到队列.
B.我想将两个线程的访问同步到队列并使用条件变量,因为其中一个线程将等待内容由另一个线程存储到队列中.
对于用例AI,请参阅代码示例std::lock_guard<>.对于用例BI,请参阅使用的代码示例std::unique_lock<>.
两者之间有什么区别,我应该在哪个用例中使用哪一个?
注意:这个问题涉及C++ 11.C++ 17(或更高版本)中相同问题的答案可能已经改变.详情如下:
当我们想要锁定多个时std::mutex,我们使用std::lock().但std::lock()不提供RAII功能.
当我们想以std::mutexRAII方式锁定时,我们使用std::lock_guard.但std::lock_guard不能std::mutex安全地锁定多个's.
有没有办法利用这两种方法的优势,以std::mutexRAII的方式锁定多个?
从这个问题我明白这std::scoped_lock是“一个严格的高级版本std::lock_guard”。
从这个问题我明白“std::lock_guard和std::unique_lock是一样的”,除了std::unique_lock有一些额外的功能(例如try_lock),但需要一些额外的开销。
与std::scoped_lock相比如何std::unique_lock?
我希望通过这个问题回答一些相关的问题。
std::scoped_lock和之间有什么区别std::unique_lock?std::scoped_lock而不是std::unique_lock?std::unique_lock而不是std::scoped_lock?std::scoped_lock实现 的一些附加功能std::unique_lock?当我从函数中返回a时std::lock_guard,std::pair我会得到可怕的错误.但是当我将它打包成一个类时,我没有任何问题(编译并按预期工作).我不明白为什么.细节如下:
我设计了一个小模板类,以便方便地锁定和解锁共享对象.它不是特别创新,但C++ 17允许它非常紧凑并且代码读/写友好:
template <typename T> class Locked {
public:
Locked(T& _object, std::mutex& _mutex)
: object(_object)
, lock(_mutex)
{
}
T& object;
std::lock_guard<std::mutex> lock;
};
template <typename T> class Lockable {
public:
Locked<T> borrow() { return Locked(object, mutex); }
Locked<const T> borrow() const { return Locked(object, mutex); }
private:
T object;
mutable std::mutex mutex;
};
Run Code Online (Sandbox Code Playgroud)
它可以像:
int main()
{
Lockable<std::vector<int>> lv;
auto [vec, lock] = lv.borrow();
std::cout << vec.size() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
我的问题是这个.这Locked堂课很瘦.我以为我可以使用std::pair …
我已经阅读了许多已经回答的与此相关的问题,但没有一个让我清楚地了解当我有多个作者但只有一个读者时应该使用哪个。下面的代码是我正在谈论的一个人为的例子。
struct StateInfo {
long wd{};
uint32_t perc{};
};
class Blah
{
const int numDevices = getDevices();
std::shared_mutex sharedMutexSI_;
vector<StateInfo> stateInfo;
public:
Blah() : stateInfo(numDevices){};
void writers(StateInfo &newSi, const int i)
{
std::shared_lock<std::shared_mutex> _MULTIPLE(sharedMutexSI_);
stateInfo[i] = newSi;
}
StateInfo reader(const int i)
{
std::lock_guard<std::shared_mutex> _EXCLUSIVE(sharedMutexSI_);
return stateInfo[i];
}
};
Run Code Online (Sandbox Code Playgroud)
情况是多个编写者可能同时更新 stateInfo 向量,但永远不会更新向量中的相同项,因为i每个线程都是唯一的。单个读取器线程可以随时尝试读取任何向量项。
上面的代码在避免竞争条件方面是否正确?
是lock_guard正确使用还是我应该使用scoped_lock或unique_lock?
语境:
我知道std::lock_guard自从c++17和std::scoped_lock.
我也知道这std::scoped_lock是首选,因为它可以处理多个互斥体,并以与之前相同的方式使用死锁避免算法std::lock。
我对我们只有一个互斥体的情况感兴趣,因此我们不需要关心避免死锁。
我从这个答案中读到:
您可以考虑
std::lock_guard弃用。的单参数情况std::scoped_lock可以作为专业化来实现,这样您就不必担心可能的性能问题。
问题:
我想知道这句话有多少是真实的。
我的意思是,是否(按照标准)保证使用单个互斥锁std::scoped_lock进行专门化,以便消除由于死锁避免处理而产生的任何不必要的开销?
我的想法:
经过对这个问题的一些调查,我从cppreference中发现了以下句子:
如果给出多个互斥体,则使用死锁避免算法,就像 一样
std::lock。
这可以让我们推断出这样的事情不会发生,否则(即,如果只给出一个互斥锁)。
但再次强调,这只是一个假设。
从这个c++ 草案中,我没有看到任何关于这种专业化的明确提及。
我得到的唯一一句话是:
当
sizeof...(MutexTypes)是 时1,提供的Mutex类型应满足Cpp17BasicLockable要求。否则,每种互斥体类型都应满足Cpp17Lockable要求。
(强调我的)
我知道BasicLockable要求要求存在满足此处定义的条件的lock()函数。
另一方面,Lockable需求假定了BasicLockable需求,并添加了满足此处定义的条件的函数。unlock()try_lock()
我知道try_lock()需要该函数才能运行std::lock.
根据上述C++草稿摘录中的说明,try_lock()如果我们只向 提供一个互斥体,则不需要该函数 …
我看过一个共享互斥锁的例子:
class MyData {
std::vector<double> data_;
mutable shared_mutex mut_; // the mutex to protect data_;
public:
void write() {
unique_lock<shared_mutex> lk(mut_);
// ... write to data_ ...
}
void read() const {
shared_lock<shared_mutex> lk(mut_);
// ... read the data ...
}
};
Run Code Online (Sandbox Code Playgroud)
我自然会写:
public:
void write() {
mut_.lock();
// ... write to data_ ...
mut_.unlock();
}
void read() const {
mut_.lock_shared();
// ... read the data ...
mut_.unlock_shared();
}
};
Run Code Online (Sandbox Code Playgroud)
我的方法也对吗?我使用的内容与示例中使用的内容之间有区别吗?另外,一个比另一个有优势吗?谢谢!
这是用于演示的简单代码片段。
有人告诉我,双重检查锁不正确。由于变量是非易失性的,编译器可以自由地重新排序调用或优化它们(有关详细信息,请参阅 codereview.stackexchange.com/a/266302/226000)。
但是我真的看到很多项目中确实使用了这样的代码片段。有人可以对这个问题有所了解吗?我用谷歌搜索并和我的朋友谈论它,但我仍然找不到答案。
#include <iostream>
#include <mutex>
#include <fstream>
namespace DemoLogger
{
void InitFd()
{
if (!is_log_file_ready)
{
std::lock_guard<std::mutex> guard(log_mutex);
if (!is_log_file_ready)
{
log_stream.open("sdk.log", std::ofstream::out | std::ofstream::trunc);
is_log_file_ready = true;
}
}
}
extern static bool is_log_file_ready;
extern static std::mutex log_mutex;
extern static std::ofstream log_stream;
}
//cpp
namespace DemoLogger
{
bool is_log_file_ready{false};
std::mutex log_mutex;
std::ofstream log_stream;
}
Run Code Online (Sandbox Code Playgroud)
更新:谢谢大家。InitFd()确实有更好的实现,但它确实只是一个简单的演示,我真正想知道的是,双重检查锁定是否存在任何潜在问题。
有关完整的代码片段,请参阅https://codereview.stackexchange.com/questions/266282/c-logger-by-template。
c++ ×8
c++17 ×5
mutex ×4
c++11 ×3
locking ×2
atomic ×1
lock-guard ×1
scoped-lock ×1
stdmutex ×1