我对lock_guard
和返回值有疑问。我想用一些代码来说明我的问题:
class Semaphore
{
public:
Semaphore() = delete;
Semaphore(int n);
/**
* Increases semaphore by one.
*/
void up()
{
std::lock_guard<std::mutex> lg(m_);
++n_;
}
/**
* Decreases semaphore by one.
*/
void down()
{
std::lock_guard<std::mutex> lg(m_);
--n_;
}
/**
* Returns the underlying value of the semaphore.
*/
int get1() const
{
std::lock_guard<std::mutex> lg(m_);
int tmp = n_;
return tmp;
}
/**
* Returns the underlying value of the semaphore.
*/
int get2() const
{
std::lock_guard<std::mutex> lg(m_);
return n_;
}
private:
mutable std::mutex m_;
int n_;
};
上面的类是Semaphore
的简单实现。哪种get方法是线程安全的? get2
是否足够好还是我必须使用get1
?我必须将内部值n_
复制到临时变量还是可以立即将其返回?
此帖子归结为以下问题:lock_guard是否保护我的返回值?
get2()
足以保护返回值。
n_
由值返回,因此将使用您的return n_
语句复制该变量以返回给调用方。您的lock_guard
将确保n_
不会被更改,直到将该副本返回给调用方,然后销毁该副本,从而释放锁定。
从在n_
上没有数据争夺的意义上来说,它们都是安全的。在lock_guard
被销毁之前,首先构造返回值。
但是,您的类方法不能以线程安全的方式使用。
[如果有任何线程先调用down()
,然后又调用get()
,则不能保证在这两个调用之间(没有锁的情况下)另一个线程可能不会先获得锁。
您必须在锁定互斥锁且无中断的同时修改并返回该值。因此,up()
和down()
必须返回n_
。不应有get()
功能。