C++ 将std::atomic与对齐的类一起使用
我有一个C++ 将std::atomic与对齐的类一起使用,c++,c++11,sse,C++,C++11,Sse,我有一个mat4类,一个使用sse内部函数的4x4矩阵。此类使用\u MM\u ALIGN16对齐,因为它将矩阵存储为一组\u m128。问题是,当我声明一个原子时,我的编译器对我大喊大叫: f:\program files (x86)\microsoft visual studio 12.0\vc\include\atomic(504): error C2719: '_Val': formal parameter with __declspec(align('16')) won't be al
mat4
类,一个使用sse内部函数的4x4矩阵。此类使用\u MM\u ALIGN16
对齐,因为它将矩阵存储为一组\u m128
。问题是,当我声明一个原子时,我的编译器对我大喊大叫:
f:\program files (x86)\microsoft visual studio 12.0\vc\include\atomic(504): error C2719: '_Val': formal parameter with __declspec(align('16')) won't be aligned
这与我尝试将任何与\u MM\u ALIGN16
对齐的类作为函数的参数传递(不使用常量&
)时遇到的错误相同
如何声明mat4类的原子版本?原子的可能有一个构造函数,该构造函数作为。例如,在使用GCC 4.5打包的原子
标题中:
97: atomic(_Tp __i) : _M_i(__i) { }
这是有问题的,原因与任何其他具有内存对齐类型作为参数的函数完全相同:函数跟踪堆栈上的内存对齐数据将非常复杂和缓慢
即使编译器允许,这种方法也会失败。假设您正在尝试优化速度,我将实现一种不太细粒度的内存访问方法。要么在执行一系列计算时锁定对内存块的访问,要么显式设计程序,使线程永远不会尝试访问同一块内存。我不知道\u declspec(align(foo))
应该如何工作,但是:
struct alignas(16)mat4{
浮动一些_浮动[4][4];
};
原子am4;
静态断言(alignof(decltype(am4))==16,
“Jabberwocky正在杀害用户。”);
int main(){
静态常数mat4 foo={{
{ 1, 2, 3, 4 },
{ 1, 2, 3, 4 },
{ 1, 2, 3, 4 },
{ 1, 2, 3, 4 }
}};
am4=foo;
}
我在MSVC中使用时遇到了类似的问题。问题发生在32位模式下。如果你在64位模式下编译,我认为你不会有这个问题。在Windows和Unix中,堆栈上的所有变量在64位模式下对齐为16字节,但在32位模式下不一定对齐。在他的手册中,他在编译时错误下写道
“错误C2719:带有uu declspec(align('16'))的形式参数将不对齐”。
Microsoft编译器无法将向量作为函数参数处理。这个
最简单的解决方案是将参数更改为常量引用,例如:
Vec4f my_函数(Vec4f const&x){
…}
因此,如果在将类传递给函数时使用const引用(如您所述),它也应该在32位模式下工作
编辑:基于此,我认为你可以使用“薄包装”。差不多
template <typename T>
struct wrapper : public T
{
wrapper() {}
wrapper(const T& rhs) : T(rhs) {}
};
struct __declspec(align(64)) mat4
{
//float x, y, z, w;
};
int main()
{
atomic< wrapper<mat4> > m; // OK, no C2719 error
return 0;
}
模板
结构包装器:public T
{
包装器(){}
包装器(常量T&rhs):T(rhs){}
};
结构declspec(align(64))mat4
{
//浮动x,y,z,w;
};
int main()
{
原子m;//好的,没有C2719错误
返回0;
}
MSC编译器在x86堆栈上从未支持超过4字节的参数对齐,因此没有解决方法
您可以通过编译
struct A { __declspec(align(4)) int x; };
void foo(A a) {}
对,
// won't compile, alignment guarantee can't be fulfilled
struct A { __declspec(align(8)) int x; };
// __m128d is naturally aligned, again - won't compile
struct A { __m128d x; };
对,
// won't compile, alignment guarantee can't be fulfilled
struct A { __declspec(align(8)) int x; };
// __m128d is naturally aligned, again - won't compile
struct A { __m128d x; };
一般而言,MSC可通过以下方式免除:
不能为函数参数指定对齐方式。
您不能指定对齐方式,因为MSC编写者希望保留决定对齐方式的自由
x86编译器使用不同的方法对齐堆栈。通过
默认情况下,堆栈是4字节对齐的。虽然这是空间
效率很高,您可以看到有些数据类型需要
8字节对齐,为了获得良好的性能,16字节
有时需要对齐。编译器可以在某些情况下确定
在某些情况下,动态8字节堆栈对齐会
特别是当堆栈上有两个值时
编译器通过两种方式实现这一点。首先,编译器可以使用
链路时间代码生成(LTCG),当用户在
编译和链接时间,以生成完整
节目。这样,它就可以确定调用树中
8字节堆栈对齐将是有益的,它决定
调用动态堆栈对齐获得最佳回报的站点。这个
当函数在堆栈上有双精度时,使用第二种方法,但是,
无论出于何种原因,尚未进行8字节对齐。编译程序
应用一种启发式方法(随着
编译器)来确定函数是否应动态
8字节对齐
因此,只要将MSC与32位平台工具集一起使用,这个问题就不可避免
x64 ABI明确了对齐方式,定义了非平凡结构或特定大小的结构作为指针参数传递。这在中进行了详细阐述,MSC必须实现这一点以与ABI兼容
路径1:使用另一个Windows编译器工具链:GCC或ICC。
路径2:移动到64位平台MSC工具集
路径3:使用T=\uu m128d
将您的用例简化为std::atomic
,因为它可以跳过堆栈并直接在XMM寄存器中传递变量。如何解决这个问题?我尝试了这个方法,但我猜它在visual studio中不起作用(或者它可以与结构一起工作,但不能与类一起工作).我试过使用薄包装器,但仍然得到完全相同的错误。我无法更改microsoft对std::atomic的实现,因此传递常量引用也不起作用。我不想强制使用64位模式……现在,作为一种解决方法,我使用std::mutex来保护对mat4的访问(它是非“原子的”)。有更好的方法吗?@HaydnV.Harach是的,锁定数据以保护访问是处理该主题的官方(POSIX)方法。在Windows上,您还可以查看互锁的操作系列,例如InterlockedExchangePointer,但如果您希望继续使用Windows上的值类型,则这不适用