Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/158.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 将std::atomic与对齐的类一起使用_C++_C++11_Sse - Fatal编程技术网

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上的值类型,则这不适用