假设我们有class A
个const方法(仅限)。
class A
{
public:
void method1() const;
void method2() const;
}
此外,我们还有另一个class B
shared_ptr
class A
以及返回它的方法,并使用互斥保护进行更改:
class B
{
std::shared_ptr<A> ptr;
std::mutex m;
public:
B()
{
ptr = std::make_shared<A>();
}
std::shared_ptr<A> getPtr() const
{
mutex_on_stack mut(m);
return ptr;
}
void resetPtr()
{
mutex_on_stack mut(m);
ptr.reset(new A());
}
}
ptr
变量受互斥锁保护,因此我认为它是线程安全的。但我不确定内在物体本身的安全性。
B objB;
//thread 1
auto p1 = objB->getPtr();
p1->method1(); //calling const method
//thread 2
auto p2 = objB->getPtr();
p2->method2(); //calling const method
//thread 3
objB->resetPtr();
线程1和2调用getPtr()
方法并在复制时增加shared_ptr
的引用计数器。所以我认为内部指针不会被线程3中的resetPtr()
意外删除。此外,方法method1
和method2
是const,因此它不会修改内部对象。但我错了。
所以我有两个问题:
class A
线程安全吗?答案 0 :(得分:1)
类A
是线程安全的,因为它只使用const
函数,可以假设它们不会改变外部可见状态。虽然const
函数能够修改内部状态,如果该类也有mutable
成员,但通常假设任何mutable
成员都是同步的,因此两个并发读者一个物体永远不会遇到竞争条件。
访问shared_ptr
的内容是线程安全的,实际上甚至不需要互斥锁的额外同步。来自cppreference:
所有成员函数(包括复制构造函数和复制赋值) 可以由shared_ptr的不同实例上的多个线程调用 即使这些实例是副本,也没有其他同步 并分享同一对象的所有权。
但是,只有当您未调用相关const
的非shared_ptr
函数时,此操作才有效:
如果多个执行线程没有访问相同的shared_ptr 同步和任何这些访问使用非const成员 shared_ptr的功能然后会发生数据竞争; shared_ptr 原子函数的重载可用于防止数据竞争。
因此,如果没有互斥锁,那么类B
现在就不会是完全线程安全的,因为你在函数上调用了reset
。如果不使用atomic overloads for shared_ptr
调用reset
而不使用互斥锁,它将成为线程安全的。
实际上,确保线程安全所需要做的唯一事情就是确保你的RAII包装器一直持续到功能范围的结束,它正在进行。
关于RAII包装器的主题,您不需要推出自己的锁定解锁机制。标准库已经为您提供了RAII锁,其形式为lock_guard
,unique_lock
和shared_lock
。像这样的简单场景可能与lock_guard
最匹配,<fieldset data-role="controlgroup" id="pilihtambahan" style="margin-top: 5px;">
</fieldset>
$.ajax({
url: host+'/skripsi3/phpmobile/tambahbarang.php',
data: { "id": getacara},
dataType: 'json',
success: function(data, status){
console.log(data);
$.each(data, function(i,item){
$("#pilihtambahan").append('<input class="tambahsewa" type="checkbox" value="'+item.idbarang+'" name="cektambah" id="'+item.idbarang+'"><label for="'+item.idbarang+'">'+item.namabarang+' @ Rp.'+item.harga+',-</label><input type="text" id="'+item.idbarang+'" name="jumsewa" placeholder="Jumlah Sewa '+item.namabarang+'"><hr>').trigger("create");
});
},
error: function(){
console.log("error");
//output.text('There was an error loading the data.');
}
});
旨在用作简单的作用域锁。