我想知道什么是使数据线程安全的"最佳"方法.
具体来说,我需要跨多个线程保护链表 - 一个线程可能尝试从中读取,而另一个线程从中添加/删除数据,甚至释放整个列表.我一直在读锁; 它们似乎是最常用的方法,但显然它们可能存在问题(死锁).我还读过关于原子操作以及线程局部存储的内容.
在您看来,什么是我最好的行动方案?大多数程序员使用的方法是什么?出于什么原因?
我一直试图找到Qt的引用计数的实现位置和方式.QBasicAtomicInt和QAtomicInt使用ref()和deref()函数,它们提供有效的引用计数API.这些函数以原子方式递增和递减值,但这些函数在库中实现的位置是什么?我试图了解Qt究竟是如何实现原子引用计数的.谢谢.
我正在尝试这两个基准测试(软件事务内存和原子操作,我猜两者都不一样),虽然我没有做太多使用STM(似乎很难使用),但我成功尝试计数基准,即所有线程将共享计数器递增50,000次,并注意到原子操作比STM更好.
所以我想知道,因为STM尚未完全开发,它们在现实情况下是否比原子操作表现良好?
有一个人因为表现而转向其他人吗?请分享信息..
我在网上找到的相关日志是没有锁的并发编程
PS我使用JAVA作为编程语言.STM: - 多节.AtomicOperatinn:AtomicInteger.
我不明白为什么会这样.拿下以下的伪代码:
volatile unsigned long count = 0;
volatile unsigned long sum = 0;
void ThreadFunction() {
InterlockedIncrement(&count);
InterlockedExchangeAdd(&sum, rand());
}
int main() {
for (int i = 0; i < 10; ++i) {
// This is the problematic instruction
InterlockedExchange(&count, 0);
InterlockedExchange(&sum, 0);
std::vector<boost::thread> threads(i);
for (int j = 0; j < i; ++j)
threads[j] = boost::thread(ThreadFunction);
while (count != i)
Sleep(0);
}
}
Run Code Online (Sandbox Code Playgroud)
在程序的第一次运行时i = 0,sum主线程的原子交换通常在生成的线程完成后发生.操作count总是以正确的顺序发生.
这只发生一次; 它以正确的顺序为循环的其余部分执行操作.它并不总是发生,但它通常会发生.如果我在原子添加之前进入调试器或睡眠,则指令将以正确的顺序执行.
无论哪种方式,结果是线程写入的值被替换为在线程被启动之前应该发生的0. …
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
Run Code Online (Sandbox Code Playgroud)
我发现increment方法在循环块中起作用.为什么我们不能在没有任何循环的情况下计算结果?什么是它?
我有一个struct包含int m_ref表示内部引用计数的整数(比如说).
为了保持C兼容性,我无法将类型更改为std::atomic<int>:struct可能只包含普通旧数据.
但是,我想调整我的代码以利用C++ 11中的原子功能; 即我需要完成:
++m_ref;
Run Code Online (Sandbox Code Playgroud)
和
--m_ref;
Run Code Online (Sandbox Code Playgroud)
作为原子操作.我目前正在使用汇编程序(英特尔总线锁)来执行此操作,但该代码几乎不可移植,而且我很想在C++提供标准构造时删除它.
不知何故,我需要进入'引擎盖'并做什么atomic<T>但没有创建原子类型的开销:我担心附加m_ref atomic<T>会降低性能.
我怀疑这是非常标准的,我在这里缺少一些简单的东西.
前几天我在网站上看到了一个问题,起初我认为答案很简单,但后来我认为不是.
如何使用原子指令实现锁定?比较和交换是原子检查某物的价值的标准方式,但它旨在用于无锁设计,因此我的困惑....
这个问题与我以前有关.我做了一些测试,并发现拥有充满原子的数组比我之前使用互斥锁的方法快得多.但拥有数百万只它可以吗?也许有些东西我根本不知道?
我正在处理Java中的一个对象,它的计算成本非常高,而且大小只有几兆字节.为了在应用程序重新启动时保留它,我想将其序列化为a File,并在启动时重新加载该文件(如果存在).
问题是大多数文件系统不是事务性的.文件写入过程可能因异常,JVM终止和/或电源故障而中断.我绝对需要断言的是,如果使用该文件,则其中的信息是完整的.如果需要,我可以丢弃信息并重新计算,但必须避免阅读和依赖不完整的数据.
我的尝试是序列化并在文件末尾写一个"seal"对象,例如校验和.反序列化期间此对象的存在可确保序列化过程完成.如果在反序列化期间没有密封对象,我知道我不能信任文件中的数据,因为它可能是不完整的.我正在寻找一个独立于操作系统的解决方案,我不需要考虑恶意修改序列化文件内容的"攻击".
我的问题是:上面列出的密封对象方法是否安全,或者是否仍有一些极端情况下我最终会在不注意的情况下读取不完整的文件?
我正在引用std :: atomic的cppreference示例,试图为堆栈添加Dtor函数:
#include<atomic>
template<class T>
struct node{
T data;
node* next;
node(const T&data):data(data),next(nullptr){}
};
template<class T>
class stack{
std::atomic<node<T>*> head;
public:
void push(const T&data)
{
node<T>* new_node=new node<T>(data);
new_node->next=head.load(std::memory_order_relaxed);
while(!std::atomic_compare_exchange_weak_explicit(
&head,
&new_node->next,
new_node,
std::memory_order_release,
std::memory_order_relaxed));
}
~stack()
{
node<T>* p=head;
while(p)
{
node<T>* next=p->next;
delete p;
p=next;
}
}
};
int main()
{
stack<int> s;
s.push(1);
s.push(2);
s.push(3);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当程序执行到〜stack时,最后一个删除功能会提示崩溃,如下所示:
$ g++ myatomic.cpp -std=c++11
$ ./a.out
*** Error in `./a.out': munmap_chunk(): invalid pointer: 0x0000000000400b00 ***
======= Backtrace: …Run Code Online (Sandbox Code Playgroud) atomic ×10
c++ ×5
c++11 ×3
java ×3
concurrency ×2
locking ×2
destructor ×1
filesystems ×1
linux ×1
multicore ×1
performance ×1
qt ×1
winapi ×1
windows ×1