让我们假设如下:
我在 Linux / Mac OS 上有两个进程。
我有mmap共享内存(或在文件中)。
然后在这两个过程中我都有以下内容:
struct Data{
volatile int reload = 0; // using int because is more standard
// more things in the future...
};
void *mmap_memory = mmap(...);
Data *data = static_cast<Data *>(mmap_memory); // suppose size is sufficient and all OK
Run Code Online (Sandbox Code Playgroud)
然后在我做的其中一个过程中:
//...
data->reload = 1;
//...
Run Code Online (Sandbox Code Playgroud)
在另一个我做的:
while(...){
do_some_work();
//...
if (data->reload == 1)
do_reload();
}
Run Code Online (Sandbox Code Playgroud)
这会是线程/进程间安全的吗?
注意:
这对于 来说并不安全std::atomic<>,因为它不“承诺”有关共享内存的任何内容。此外,从两个不同的过程构建/销毁根本不清楚。
std::atomic<bool> x{ false };
std::atomic<bool> y{ false };
// thread 1
y.store(true, std::memory_order_seq_cst);
x.store(true, std::memory_order_release);
// thread2
while (!x.load(std::memory_order_relaxed);
assert(y.load(std::memory_order_seq_cst)); // !!!
Run Code Online (Sandbox Code Playgroud)
断言会失败吗?我的理解是:虽然读取x是“放松的”,但一旦“线程2”看到“线程1”的写入,它就看不到y,false因为写入y发生在写入之前x。
内存顺序是从现实生活中的案例复制的,对于这个示例来说可能会更弱,但我没有改变它,以免错过任何微妙之处。
我有一个与此类似的线程类:
class thr {
void run() {
for (;;) {
// block on a queue
// do some processing
++loops_;
}
}
void get_metrics(int& qps) {
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
double delta = std::chrono::duration<double>(now - last_metrics_time_).count();
qps = std::round(loops_ / delta);
loops_ = 0;
last_metrics_time_ = now;
}
static std::atomic<int> loops_;
static std::chrono::steady_clock::time_point last_metrics_time_;
};
std::atomic<int> thr::loops_ { 0 };
std::chrono::steady_clock::time_point thr::last_metrics_time_ {
std::chrono::steady_clock::now() // initial value: when the program starts
};
Run Code Online (Sandbox Code Playgroud)
这种运行有很多例子.还有另一个线程不时调用get_metrics().
我想阻止run()能够访问last_metrics_time_,因为它不是原子的(只有一个度量收集器线程,所以没有问题).
将last_metrics_time_ …
根据https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57250,GCC 4.9支持原子shared_ptr操作.
使用GCC 4.9.2,我能够编译一个使用原子的程序shared_ptr.该-mcx16标志是必需的,因为x86_64上的GCC实现显然需要cmpxchg16b,这是有道理的,因为我认为对a的原子操作shared_ptr需要同时原子地更新指针本身和引用计数.
但是,当我尝试实际使用原子shared_ptr库时,它的行为并不像我期望的那样.所以,要么我没有正确使用它,要么GCC实现有缺陷.大部分时间我都有99%的自信我只是做错了,但由于这是一个相对较新的功能,而且由于行为看起来很奇怪,我只有50%的信心,这是我的错案件.
这是一个创建原子的简单程序shared_ptr,然后在shared_ptr上执行一系列并发读写:
void test()
{
std::atomic<std::shared_ptr<int>> p(std::shared_ptr<int>(new int(10)));
std::cout << "Use count : " << p.load().use_count() << std::endl;
std::cout << "Initial value of p : " << *(p.load()) << std::endl;
std::vector<std::thread> threads;
const std::size_t num_threads = 8;
for (std::size_t i = 0; i != num_threads; ++i)
{
threads.emplace_back([&p, i](){
std::shared_ptr<int> x = p.load();
while (!p.compare_exchange_weak(
x,
std::shared_ptr<int>(new int(i + …Run Code Online (Sandbox Code Playgroud) 以下代码(从大型项目中最小化)在使用XCode 7.3.1,针对iOS的Boost 1.61构建时导致EXC_BAD_INSTRUCTION崩溃:
main.mm:
#include "stdio.h"
#include "boost/lockfree/queue.hpp"
int main(int argc, char * argv[]) {
printf("Test1 in\n");
boost::lockfree::queue<int*> q(100);
printf("Test1 out\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
stacktrace似乎告诉我,问题来自c ++原子操作:
#0 0x0000000100047a78 in std::__1::__atomic_base<boost::lockfree::detail::tagged_ptr<boost::lockfree::detail::freelist_stack<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node, std::__1::allocator<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node> >::freelist_node>, false>::store(boost::lockfree::detail::tagged_ptr<boost::lockfree::detail::freelist_stack<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node, std::__1::allocator<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node> >::freelist_node>, std::__1::memory_order) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/atomic:842
#1 0x0000000100047a74 in boost::lockfree::detail::freelist_stack<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node, std::__1::allocator<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node> >::deallocate_impl_unsafe(boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node*) at /Users/deinzer/src/pipeline.ios/boost/boost/lockfree/detail/freelist.hpp:251
#2 0x00000001000479e8 in boost::lockfree::detail::freelist_stack<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node, std::__1::allocator<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node> >::freelist_stack<std::__1::allocator<boost::lockfree::queue<int*, …Run Code Online (Sandbox Code Playgroud) 我如何使用std::atomic<T>::is_always_lock_freeSFINAE?我有一个类模板MyClass<T>,我想,2个实现之间切换取决于是否std::atomic<T>::is_always_lock_free是true.这就是我所拥有的:
template<typename T, typename Enable = void>
class MyClass {
// Fallback implementation
};
template<typename T>
class MyClass<T, typename std::enable_if<std::atomic<T>::is_always_lock_free>::type> {
// Optimized implementation using std::atomic
};
Run Code Online (Sandbox Code Playgroud)
现在,当我尝试创建一个实例时MyClass<SomeCustomClass>,我得到一个编译器错误:
_Atomic不能应用于类型'SomeCustomClass',它不是可轻易复制的
它尝试使用模板特化,但不使用回退实现,它根本不编译.有人可以解释这里有什么问题吗?我如何获得理想的结果?
我把一个自定义类Unit放在一个std::atomic.使用默认构造函数,类看起来如下所示
namespace Base
{
template <typename T, typename R, typename D>
class Unit
{
public:
constexpr Unit() = default;
private:
T m_Value;
};
}
Run Code Online (Sandbox Code Playgroud)
它曾经工作正常,直到我注意到我忘了在默认构造函数中将我的类的唯一成员初始化为零.因此我删除了= default并提供了构造函数的实现
template <typename T, typename R, typename D>
constexpr Unit<T, R, D>::Unit() :
m_Value(T(0))
{ }
Run Code Online (Sandbox Code Playgroud)
现在我收到编译器错误:
Error C2280 'std::atomic<Base::Unit>::atomic(void) noexcept': attempting to reference a deleted function
我的预感是因为我现在提供了一个自定义构造函数,这导致默认的复制构造函数不再被隐式定义.
所以,我也把这个添加到了类声明中
Unit(const Unit<T, R, D>& U) = default;
Run Code Online (Sandbox Code Playgroud)
但是,我得到了同样的错误.我不确定我能成为什么样的人.我不确定编译器指的是哪个删除的函数.
任何帮助,将不胜感激
编译以下代码时(gcc-4.8,--std=c++11):
#include <atomic>
#include <utility>
#include <cstdint>
struct X {
std::atomic<std::pair<uint32_t, uint32_t>> A;
};
Run Code Online (Sandbox Code Playgroud)
我收到以下编译错误:
Run Code Online (Sandbox Code Playgroud)/usr/local/include/c++/4.8.2/atomic:167:7: error: function 'std::atomic<_Tp>::atomic() [with _Tp = std::pair<unsigned int, unsigned int>]' defaulted on its first declaration with an exception-specification that differs from the implicit declaration 'constexpr std::atomic<std::pair<unsigned int, unsigned int> >::atomic()'
使用较新的编译器(带有的gcc-9 --std=c++17),我得到:
Run Code Online (Sandbox Code Playgroud)In instantiation of 'struct std::atomic<std::pair<int, int> >': error: static assertion failed: std::atomic requires a trivially copyable type static_assert(__is_trivially_copyable(_Tp),
演示:
我不知道为什么。有人可以帮我吗?
对不起,如果我的怀疑太幼稚。但我有一个类型转换难度std::atomic要char*类型。是强制转换std::atomic to char有效吗?
我可以写这样的类型转换变量。我确信当线程试图将变量写入变量时不会有多线程读/写操作(我知道,当该变量没有并发访问时,就不需要使用原子)。
std::atomic<uint8_t>* data_;
char *data = reinterpret_cast<char*>(data_);
*data |= mask;
Run Code Online (Sandbox Code Playgroud)
安全吗?
编辑:我不确定是否值得一提。在我的代码中
char *raw;
// variable raw is allocated
std::atomic<uint8_t>* data_ = reinterpret_cast<std::atomic<uint8_t>*>(raw);
Run Code Online (Sandbox Code Playgroud)
上面是std::atomic< uint8_t>创建方法的方式(作为char和type强制转换为std :: atomic类型)。
谢谢 :)
我的程序很简单,我想使用原子类型。可以使用int,double但不能使用std::string。
#include <iostream>
#include <atomic>
#include <string>
int main()
{
std::atomic<int> test(0); // works
std::cout<<test; // will print 0
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果我更改为
std::atomic<std::string> test("0");
Run Code Online (Sandbox Code Playgroud)
它将给出此错误
/ usr / include / c ++ / 6 / atomic:在'struct std :: atomic>'的实例中:main.cpp:16:34:
从此处需要/ usr / include / c ++ / 6 / atomic:178:7:错误:静态断言失败:std :: atomic需要一个普通可复制类型static_assert(__ is_trivially_copyable(_Tp),^ ~~~~~~~~~~~~~
我已经使用C ++ 17,C ++ 14和C ++ 11测试了该代码。遵循此线程std :: atomic <std :: string>是否正常工作?原子字符串应该可以正常工作,但是出现了这个错误。这是什么原因呢?以及如何std::atomic<std::string>正确使用?
c++ ×10
stdatomic ×10
atomic ×3
arm ×1
boost ×1
c++-chrono ×1
c++17 ×1
constructor ×1
gcc ×1
ios ×1
shared-ptr ×1
std-pair ×1
stdstring ×1
volatile ×1