当我正在阅读有关内存模型,障碍,排序,原子等等时,编译器栅栏的概念经常会出现,但通常情况下,它也会与CPU栅栏配对,正如人们所期望的那样.
但是,偶尔我会读到仅适用于编译器的fence构造.一个例子是C++ 11 std::atomic_signal_fence函数,它在cppreference.com上声明:
std :: atomic_signal_fence等效于std :: atomic_thread_fence,除了没有发出内存排序的CPU指令.仅按顺序指示抑制编译器对指令的重新排序.
我有五个与此主题相关的问题:
正如名称所暗示的那样std::atomic_signal_fence,是一个异步中断(例如一个被内核抢占以执行信号处理程序的线程)唯一一种只有编译器的栅栏才有用的情况?
它的用处是否适用于所有体系结构,包括强烈排序的体系结构x86?
是否可以提供一个特定的示例来演示仅编译器栅栏的用途?
使用时std::atomic_signal_fence,使用acq_rel和seq_cst订购之间有什么区别吗?(我希望它没有任何区别.)
这个问题可能是由第一个问题所覆盖,但我足够的好奇,一下也无妨具体问:是否曾经需要使用围栏与thread_local访问?(如果有的话,我希望只有编译器的围栏atomic_signal_fence才能成为首选工具.)
谢谢.
boost::reference_wrapper<T>有一个显式的 T&构造函数,而std::reference_wrapper<T>有一个隐式的构造函数.因此,在以下代码中:
foo = bar;
Run Code Online (Sandbox Code Playgroud)
如果foo是a boost::reference_wrapper,则代码将无法编译(这很好,因为reference_wrapper它没有与实际引用相同的语义.
如果foo是a std::reference_wrapper,则代码将"重新绑定"对其foo的引用bar(而不是像人们可能错误地指望的那样分配值).
这可能导致难以捉摸的错误......请考虑以下示例:
在某些假设库的1.0版中:
void set_max(int& i, int a, int b) {
i = (a > b) ? a : b;
}
Run Code Online (Sandbox Code Playgroud)
在新版本(1.1)中,set_max转换为模板以接受任何宽度(或UDT)的整数而不更改接口:
template<typename T1, typename T2, typename T3>
void set_max(T1& i, T2 a, T3 b) {
i = (a > b) ? a : …Run Code Online (Sandbox Code Playgroud) 我有一些非常简单的(C++ 11)代码,最新的clang(版本3.4 trunk 187493)无法编译,但GCC编译得很好.
代码(下面)foo使用函数本地类型 实例化函数模板,Bar然后尝试将其地址用作类模板的非类型模板参数Func:
template<void(*FUNC_PTR)(void)>
struct Func {};
template<typename T> extern inline
void foo() {
using Foo = Func<foo<T>>;
}
int main() {
struct Bar {}; // function-local type
foo<Bar>();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
clang发出以下错误:
错误:非类型模板参数是指没有链接的函数'foo'
但是,如果我将类型移动Bar到全局范围(通过将其从函数中取出),则clang可以很好地编译它,证明问题在于函数本地类型.
那么clang是否正确发出此错误,或者标准是否不支持这种情况(在这种情况下,GCC通过允许它过于宽松)?
using声明从foo<Bar>()范围移到main()范围):
template<void(*FUNC_PTR)(void)>
struct Func …Run Code Online (Sandbox Code Playgroud) 我知道检查类型是否是采用TYPE参数的类模板的实例化是很简单的,如下所述:如何检查类型是否是给定类模板的实例化?
但是......是否有可能有一个可变的"is_instantiation_of__ntp <...>"(NTP代表非类型参数),它将接受具有任意数量的异构 NON-TYPE参数的模板?例如:
template<char*, bool, long, size_t, char>
struct many_hetero_nontype_params_example {};
char HELLO_WORLD[] = "hello world";
using ManyHeteroNontypeParamsEx = many_hetero_nontype_params_example<HELLO_WORLD, false, -16, 777, 'x'>;
Run Code Online (Sandbox Code Playgroud)
并能够如下使用它:
is_instantiation_of__ntp<char*, bool, long, size_t, char, many_hetero_nontype_params_example, ManyHeteroNontypeParamsEx>::value
Run Code Online (Sandbox Code Playgroud)
我知道这可以很容易地实现NON-TYPE参数列表,这些参数列表是1)"同类"(相同类型的值),或2)很少的参数(这样非可变解决方案是实用的).我甚至写了一个测试用例来演示这些特殊情况(用gcc 4.7.0编译),以便更好地了解我在说什么:
namespace test__is_instantiation_of__
{
// is_instantiation_of
template< template<typename...> class Template, typename T >
struct is_instantiation_of : std::false_type {};
template< template<typename...> class Template, typename... Args >
struct is_instantiation_of< Template, Template<Args...> > : std::true_type {};
// is_instantiation_of__homogeneous_nontype_params__
template< typename NTP, template<NTP...> class Template, …Run Code Online (Sandbox Code Playgroud) c++ templates template-meta-programming variadic-templates c++11
在以下代码中(为演示而简化):
namespace mpl = boost::mpl;
using if1 = mpl::if_<std::is_same<double, mpl::_1>, double, void>;
//using if2 = mpl::if_<std::is_same<double, mpl::_1>, typename std::common_type<double, mpl::_1>::type, void>;
using apply1 = boost::mpl::apply<if1, double>::type;
//using apply2 = boost::mpl::apply<if2, double>::type;
Run Code Online (Sandbox Code Playgroud)
在std::is_same<double, mpl::_1>,占位符被正确替换double,就好像实例化明确std::is_same<double, double>导致正确/预期的行为.
但是,在std::common_type<double, mpl::_1>占位符中没有替换占位符,就好像实例化是明确的std::common_type<double, mpl_::arg<1>>,这会导致以下错误,因为显然没有"常见"类型:
error: incompatible operand types ('double' and 'mpl_::arg<1>')
Run Code Online (Sandbox Code Playgroud)
问题:为什么mpl::_1占位符正确转换/置换double的std::is_same,而不是在std::common_type?有解决方法吗?
我使用boost::mpl::string<...>类型广泛......以至于它会真的与调试有类型适合打印帮助gdb.
所以...而不是gdb像目前那样显示单个(多字符文字)组件......
boost::mpl::string<1668248165, 778856802, 778858343, ..., ..., 0, 0, 0, 0, 0, 0>
Run Code Online (Sandbox Code Playgroud)
它会显示等效的字符串值而不是......
boost::mpl::string<"The way out is through">
Run Code Online (Sandbox Code Playgroud)
我已经看过gdb用于漂亮打印STL容器的宏和python脚本gdb,但我找不到一个漂亮的打印boost::mpl字符串.有人能帮忙吗?
更新:我添加了一个+100赏金......我要找的是采用了最新的GDB支持通过Python漂亮的印刷(如描述的解决方案在这里对STL容器).
我可以gcc使用used和noinline 函数属性轻松实现这一点(参见下面的代码),但这并不适用,clang即使它应该支持这两个函数属性.
一个简化的例子:
template<typename T>
struct Factory {
static __attribute__((used, noinline))
T createFoo() { return T(); }
};
int main() {
Factory<int> f; // instantiate and use Factory<int>
}
Run Code Online (Sandbox Code Playgroud)
编译代码gcc并使用nm确认gcc正确发出函数:
nm --demangle test | grep createFoo
0000000000403185 W Factory<int>::createFoo()
Run Code Online (Sandbox Code Playgroud)
代码编译良好clang,但它不会createFoo()像它应该的那样为静态函数发出代码.
如何强制clang发出从未引用过的静态函数?
从shm_open手册页:
新的共享内存对象最初的长度为零.可以使用ftruncate(2)设置对象的大小.[...] shm_open()函数本身不会创建指定大小的共享对象,因为这样做会复制现有函数,该函数设置文件描述符引用的对象的大小.
这不会使应用程序暴露于竞争条件吗?考虑以下伪代码:
int fd = shm_open("/foo", CREATE);
if ( fd is valid ) {
// created shm object, so set its size
ftruncate(fd, 128);
} else {
fd = shm_open("/foo", GET_EXISTING);
}
void* mem = mmap(fd, 128);
Run Code Online (Sandbox Code Playgroud)
由于shm_open和ftruncate调用(一起)不是原子的,你可能有一个竞争条件,一个进程调用shm_open(CREATEcase),但是在调用之前ftruncate,另一个进程调用shm_open(GET_EXISTINGcase)并尝试mmap0大小的对象,甚至可能写入它.
我可以想到两种避免这种竞争条件的方法:
使用IPC互斥量/信号量使整个事物同步,或者......
如果它是安全的(按POSIX),请ftruncate同时调用CREATE和GET_EXISTING案例.
哪种方法可以避免这种竞争条件?
我需要一种方法来根据其 alpha 蒙版向透明 PNG 图像添加“描边”(轮廓)和阴影效果,而我能找到的唯一解决方案是使用自定义 SVG 滤镜。(注意:我需要这些效果的网络应用程序是供我自己私人使用的,因此该解决方案与旧版浏览器不兼容也没关系。继续...)
我以前从未使用过 SVG,但单独创建描边和阴影滤镜非常简单。不幸的是,我无法找到一种方法来创建组合效果,而不需要将过滤器实际复制并粘贴到新过滤器中,如下面的代码所示:
<svg width="0" height="0" xmlns="http://www.w3.org/2000/svg">
<!-- drop shadow -->
<filter id="drop-shadow">
<feGaussianBlur in="SourceAlpha" stdDeviation="4" />
<feOffset result="m_offsetBlurred" dx="12" dy="12" />
<feFlood result="m_floodTrans50" flood-color="rgba(0,0,0,0.5)" />
<feComposite result="m_offsetBlurredTrans50" in="m_floodTrans50" in2="m_offsetBlurred" operator="in" />
<feMerge>
<feMergeNode in="m_offsetBlurredTrans50" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<!-- outer stroke -->
<filter id="outer-stroke">
<!-- create rectangle of the desired color -->
<feFlood result="m_floodRect" flood-color="black" />
<!-- create copy of png's alpha mask and expand -->
<feMorphology result="m_expandedMask" …Run Code Online (Sandbox Code Playgroud) 是(理论上)线程可以acquire在一个CPU上执行,然后立即被抢占并在另一个acquire从未执行过的CPU上恢复(因此根据发布 - 获取语义从不同步)?
对于前者 考虑以下使用C++ 11原子和release-acquire内存排序的代码来执行无锁线程安全初始化:
if ( false == _initFlag.load(memory_order_acquire) ) {
_foo = ...; // initialize global
_bar = ...; // initialize global
... = ...; // initialize more globals
_initFlag.store(true, memory_order_release);
}
// use the initialized values ...
Run Code Online (Sandbox Code Playgroud)
如果_initFlag.load(memory_order_acquire)返回true,则调用线程会知道的初始化值_foo,_bar等...可见(传播)到CPU 上,它目前正在执行.但是如果线程在之后立即被抢占并移动到另一个CPU怎么办?
C++ 11标准是否保证新CPU将同步?是否有任何可能容易受到此类竞争条件影响的实施或架构?
在C++中,是否有任何方法可以使用"抽象"基类方法(即,从基类声明和调用,但在子类中实现)而不将该方法声明为virtual?
当然,这个问题仅适用于不需要多态的情况(指针/对基类型的引用从未使用过).考虑以下:
#define NO_OPT asm volatile (""); // to prevent some compiler optimization
template<typename DerivedType>
void doSomething(DerivedType& d) { d.foo(); }
namespace test1 {
struct Base {
inline void foo()
{
// ... do common stuff pre-call ...
foo_impl();
// ... do common stuff post-call ...
}
virtual void foo_impl() = 0; // the abstract method
};
struct D1 : public Base { virtual void foo_impl() final { NO_OPT } };
struct D2 : public Base …Run Code Online (Sandbox Code Playgroud) 我对C++ 11的std::memory_order类型有一个很好的概念性理解(轻松与获取 - 发布与顺序一致 ......),但我想更好地理解它们通常是如何为x86实现的(通过编译器)(或x86_64)目标.
具体而言,低级别的细节(例如用于处理器之间的同步状态或高速缓存存储器的重要相关的CPU指令)为每个顺序的限制进行比较(memory_order_consume,memory_order_acquire,memory_order_release,和memory_order_seq_cst).
请提供尽可能多的低级细节,最好是x86_64或类似架构.非常感谢您的帮助.
假设您有一个可变参数函数模板,它采用仿函数和一系列同类型,并且您希望使用它std::accumulate来折叠序列,如下所示:
template<typename BinaryFuncType, typename... ArgTypes>
do_something(const BinaryFuncType& f, const ArgTypes&... objects)
{
// ...
// use std::accumulate to fold 'objects' using 'f'
// ...
}
Run Code Online (Sandbox Code Playgroud)
是否有可能通过一个可变参数(objects)的范围算法(std::accumulate)直接的,即,不会导致对象复制的费用(或引用)到一个可迭代容器?