目录 搜索
Algorithms Algorithms(算法) bsearch bsearch_s qsort qsort_s Atomic operations Atomic operations library(原子操作库) ATOMIC_*_LOCK_FREE atomic_compare_exchange_strong atomic_compare_exchange_strong_explicit atomic_compare_exchange_weak atomic_compare_exchange_weak_explicit atomic_exchange atomic_exchange_explicit atomic_fetch_add atomic_fetch_add_explicit atomic_fetch_and atomic_fetch_and_explicit atomic_fetch_or atomic_fetch_or_explicit atomic_fetch_sub atomic_fetch_sub_explicit atomic_fetch_xor atomic_fetch_xor_explicit atomic_flag atomic_flag_clear atomic_flag_clear_explicit ATOMIC_FLAG_INIT atomic_flag_test_and_set atomic_flag_test_and_set_explicit atomic_init atomic_is_lock_free atomic_load atomic_load_explicit atomic_signal_fence atomic_store atomic_store_explicit atomic_thread_fence(线程围栏) ATOMIC_VAR_INIT kill_dependency memory_order(内存排序) C keywords auto(自动存储) break(跳出循环) C keywords(关键词) case char const(常量修饰符) continue default(预设运算式) do double(双精度浮点型) else enum(枚举类型) extern(全局变量) float(浮点数) for fortran goto(goto语句) if(if语句) inline(行内函式) int long(长整型) register(寄存器变量) restrict( restrict类型限定符) return short signed sizeof(sizeof运算符) static(静态变量) struct(结构体) switch(switch语句) typedef(typedef关键字) union(联合体) unsigned(无符号) void(空类型) volatile(volatile变量) while(while语句) _Alignas _Alignof _Atomic _Bool _Complex _Generic _Imaginary _Noreturn _Static_assert _Thread_local C language #define directive #elif directive #else directive #endif directive #error directive #if directive #ifdef directive #ifndef directive #include directive #line directive #pragma directive alignas(对齐指定符) Alternative operators and tokens(替代运算符和令牌) Analyzability Arithmetic operators Arithmetic types Array declaration(数组声明) Array initialization(阵列初始化) ASCII Chart Assignment operators(赋值运算符) types(atomic类型限定符) Basic concepts Bit fields(位域) break statement C language C Operator Precedence cast operator character constant(字符字面量) Comments(注释符) Comparison operators(比较运算符) compound literals(符合字面量) Conditional inclusion(条件包含) Conformance(一致性) const type qualifier(const 限定符) Constant expressions(常量表达) continue statement Declarations(声明) do-while loop Enumerations(枚举类型) Escape sequences(转义字符) Expressions(表达式) External and tentative definitions(外部和暂定的定义) File scope(文件范围) floating constant(浮点常量) for loop Function declarations(函数声明) Function definitions(函数声明) Functions Generic selection泛型选择 goto statement Identifier(标示符) if statement Implicit conversions(隐式转换) Increment/decrement operators(前置/后置操作符) Initialization(初始化) inline function specifier(内联函式) integer constant Lifetime(生命期) Logical operators(逻辑运算符) Lookup and name spaces Main function(主函式) Member access operators(会员接入运营商) Memory model Objects and alignment(字节对齐) Order of evaluation(评估顺序) Other operators Phases of translation(翻译阶段) Pointer declaration Preprocessor(预处理) restrict type qualifier(restrict类型限定符) return statement Scalar initialization(标量类型初始化) Scope(范围) sizeof operator(sizeof运算符) Statements(陈述) static assert declaration(静态断言声明) Static storage duration(静态存储周期) Storage-class specifiers(存储类说明符) string literals(字符串字面量) Struct and union initialization(结构体与联合体初始化) Struct declaration(结构体声明) switch statement Thread storage duration(线程存储时间) Type Type(类型) Typedef declaration(Typedef声明) Undefined behavior(未定义行为) Union declaration(联合体声明) Value categories(值类别) Variadic arguments(变长参数宏) volatile type qualifier(volatile 类型限定符) while loop _Alignof operator _Noreturn function specifier Date and time asctime(asctime函数) asctime_s clock CLOCKS_PER_SEC clock_t ctime(ctime函数) ctime_s Date and time utilities(日期和时间库) difftime(计算两个时间的间隔) gmtime gmtime_s localtime localtime_s mktime(将时间结构数据转换成经过的秒数的函数) strftime(格式化输出时间函数) time timespec timespec_get time_t tm wcsftime(格式化时间宽字符) Dynamic memory management aligned_alloc C memory management library(内存管理库) calloc free(释放动态分配空间的函数) malloc(动态分配内存空间的函数) realloc(重新分配内存空间的函数) Error handling abort_handler_s assert(断言) constraint_handler_t errno(错误报告) Error handling(错误处理) Error numbers(错误个数) ignore_handler_s set_constraint_handler_s static_assert File input/output clearerr(清除/复位) fclose feof ferror fflush(清空文件缓冲区) fgetc fgetpos fgets fgetwc fgetws File input/output fopen fopen_s fprintf fprintf_s fputc fputs fputwc fputws fread freopen freopen_s fscanf fscanf_s fseek fsetpos ftell fwide fwprintf fwprintf_s fwrite fwscanf fwscanf_s getc getchar gets gets_s getwchar perror printf printf_s putc putchar puts putwc putwchar remove rename rewind scanf scanf_s setbuf setvbuf snprintf sprintf sscanf sscanf_s swprintf swprintf_s swscanf swscanf_s tmpfile tmpfile_s tmpnam tmpnam_s ungetc ungetwc vfprintf vfprintf_s vfscanf vfscanf_s vfwprintf vfwprintf_s vfwscanf vfwscanf_s vprintf vprintf_s vscanf vscanf_s vsnprintf vsprintf vsscanf vsscanf_s vswprintf vswprintf_s vswscanf vswscanf_s vwprintf vwprintf_s vwscanf vwscanf_s wprintf wprintf_s wscanf wscanf_s Localization support lconv LC_ALL LC_COLLATE LC_CTYPE LC_MONETARY LC_NUMERIC LC_TIME localeconv Localization support setlocale Numerics abs acos acosf acosh acoshf acoshl acosl asin asinf asinh asinhf asinhl asinl atan atan2 atan2f atan2l atanf atanh atanhf atanhl atanl cabs cabsf cabsl cacos cacosf cacosh cacoshf cacoshl cacosl carg cargf cargl casin casinf casinh casinhf casinhl casinl catan catanf catanh catanhf catanhl catanl cbrt cbrtf cbrtl ccos ccosf ccosh ccoshf ccoshl ccosl ceil ceilf ceill cexp cexpf cexpl cimag cimagf cimagl clog clogf clogl CMPLX CMPLXF CMPLXL Common mathematical functions complex Complex number arithmetic conj conjf conjl copysign copysignf copysignl cos cosf cosh coshf coshl cosl cpow cpowf cpowl cproj cprojf cprojl creal crealf creall csin csinf csinh csinhf csinhl csinl csqrt csqrtf csqrtl ctan ctanf ctanh ctanhf ctanhl ctanl div double_t erf erfc erfcf erfcl erff erfl exp exp2 exp2f exp2l expf expl expm1 expm1f expm1l fabs fabsf fabsl fdim feclearexcept fegetenv fegetexceptflag fegetround feholdexcept feraiseexcept fesetenv fesetexceptflag fesetround fetestexcept feupdateenv FE_ALL_EXCEPT FE_DFL_ENV FE_DIVBYZERO FE_DOWNWARD FE_INEXACT FE_INVALID FE_OVERFLOW FE_TONEAREST FE_TOWARDZERO FE_UNDERFLOW FE_UPWARD Floating-point environment float_t floor floorf floorl fma fmaf fmal fmax fmaxf fmaxl fmin fminf fminl fmod fmodf fmodl fpclassify FP_INFINITE FP_NAN FP_NORMAL FP_SUBNORMAL FP_ZERO frexp frexpf frexpl HUGE_VAL HUGE_VALF HUGE_VALL hypot hypotf hypotl I ilogb ilogbf ilogbl imaginary imaxabs imaxdiv INFINITY isfinite isgreater isgreaterequal isinf isless islessequal islessgreater isnan isnormal isunordered labs ldexp ldexpf ldexpl ldiv lgamma lgammaf lgammal llabs lldiv llrint llrintf llrintl llround llroundf llroundl log log10 log10f log10l log1p log1pf log1pl log2 log2f log2l logb logbf logbl logf logl lrint lrintf lrintl lround lroundf lroundl MATH_ERREXCEPT math_errhandling MATH_ERRNO modf modff modfl nan NAN nanf nanl nearbyint nearbyintf nearbyintl nextafter nextafterf nextafterl nexttoward nexttowardf nexttowardl Numerics pow powf powl Pseudo-random number generation rand RAND_MAX remainder remainderf remainderl remquo remquof remquol rint rintf rintl round roundf roundl scalbln scalblnf scalblnl scalbn scalbnf scalbnl signbit sin sinf sinh sinhf sinhl sinl sqrt sqrtf sqrtl srand tan tanf tanh tanhf tanhl tanl tgamma tgammaf tgammal trunc truncf truncl Type-generic math _Complex_I _Imaginary_I Program support abort atexit at_quick_exit exit EXIT_FAILURE EXIT_SUCCESS getenv getenv_s jmp_buf longjmp Program support utilities quick_exit raise setjmp SIGABRT SIGFPE SIGILL SIGINT signal SIGSEGV SIGTERM sig_atomic_t SIG_DFL SIG_ERR SIG_IGN system _Exit Strings atof atoi atol atoll btowc c16rtomb c32rtomb char16_t char32_t isalnum isalpha isblank iscntrl isdigit isgraph islower isprint ispunct isspace isupper iswalnum iswalpha iswblank iswcntrl iswctype iswdigit iswgraph iswlower iswprint iswpunct iswspace iswupper iswxdigit isxdigit mblen mbrlen mbrtoc16 mbrtoc32 mbrtowc mbsinit mbsrtowcs mbsrtowcs_s mbstate_t mbstowcs mbstowcs_s mbtowc memchr memcmp memcpy memcpy_s memmove memmove_s memset memset_s Null-terminated byte strings Null-terminated multibyte strings Null-terminated wide strings strcat strcat_s strchr strcmp strcoll strcpy strcpy_s strcspn strerror strerrorlen_s strerror_s Strings library strlen strncat Thread support call_once cnd_broadcast cnd_destroy cnd_init cnd_signal cnd_timedwait cnd_wait mtx_destroy mtx_init mtx_lock mtx_plain mtx_recursive mtx_timed mtx_timedlock mtx_trylock mtx_unlock once_flag ONCE_FLAG_INIT thrd_busy thrd_create thrd_current thrd_detach thrd_equal thrd_error thrd_exit thrd_join thrd_nomem thrd_sleep thrd_success thrd_timedout thrd_yield Thread support library thread_local tss_create tss_delete TSS_DTOR_ITERATIONS tss_get tss_set Type support Boolean type support library Fixed width integer types FLT_EVAL_METHOD FLT_ROUNDS max_align_t NULL Numeric limits offsetof ptrdiff_t size_t Type support Variadic functions Variadic functions va_arg va_copy va_end va_list va_start
文字

在头文件<stdatomic.h>中定义



enum memory_order {memory_order_relaxed,memory_order_consume,memory_order_acquire,memory_order_release,memory_order_acq_rel,memory_order_seq_cst};


(自C11以来)

memory_order指定如何在原子操作周围定期进行非原子内存访问。在多核系统上不存在任何约束时,当多个线程同时读取和写入多个变量时,一个线程可以按照与另一个线程写入它们的顺序不同的顺序观察值的变化。事实上,在多个读者线程中,更改的顺序甚至可能不同。由于内存模型允许的编译器转换,即使在单处理器系统上也会出现类似的效果。

语言和库中的所有原子操作的默认行为提供了顺序一致的排序(参见下面的讨论)。该默认值可能会损害性能,但可以给库的原子操作提供额外的memory_order参数,以指定编译器和处理器必须为该操作强制执行的确切约束,而不仅限于原子性。

常量

| 在头文件<stdatomic.h> |中定义

|:----|

| Value | Explanation |

| memory_order_relaxed | 轻松的操作:对其他读取或写入没有同步或排序约束,只保证此操作的原子性(请参阅下面的轻松排序)。

| memory_order_consume | 使用此内存顺序的加载操作会在受影响的内存位置执行消耗操作:根据当前加载的值,当前线程中的读取或写入操作在此加载之前可以重新排序。在释放相同原子变量的其他线程中写入数据相关变量在当前线程中可见。在大多数平台上,这仅影响编译器优化(请参阅下面的Release-Consume命令)|

| memory_order_acquire | 使用此内存顺序的加载操作对受影响的内存位置执行获取操作:在此加载之前,当前线程中的读取或写入操作不能重新排序。在当前线程中可以看到释放相同原子变量的其他线程中的所有写入操作(请参阅下面的Release-Acquire命令)|

| memory_order_release | 与此存储器顺序的存储操作执行释放操作:没有读取或在当前线程可以在此存储之后被重新排序写入。在当前线程所有写是在获得相同的原子变量其他线程可见(见发布 - 采集以下的订购)和写携带的依赖到原子变量中消耗相同的原子其他线程变得可见(见释放,消费订购如下)。|

| memory_order_acq_rel | 使用该存储器命令的读取 - 修改 - 写入操作既是获取操作又是释放操作。在当前线程中没有内存读取或写入可以在该存储之前或之后重新排序。在其他线程中释放相同原子变量的所有写操作在修改之前都是可见的,并且修改在获取相同原子变量的其他线程中可见。|

| memory_order_seq_cst | 此存储器订单的任何操作都是采集操作和释放操作,并且存在单个总订单,其中所有线程都以相同的顺序观察所有修改(请参见下面的按顺序一致的排序)。

轻松订购

标记的原子操作memory_order_relaxed不是同步操作; 它们不会在并发内存访问中强加一个顺序。他们只保证原子性和修改顺序的一致性。

例如,对于xy最初为零,

// Thread 1:

r1 = atomic_load_explicit(y, memory_order_relaxed); // A

atomic_store_explicit(x, r1, memory_order_relaxed); // B

// Thread 2:

r2 = atomic_load_explicit(x, memory_order_relaxed); // C

atomic_store_explicit(y, 42, memory_order_relaxed); // D.

被允许产生r1 == r2 == 42,因为尽管A被测序-之前线程1中B和C 之前测序线程2内d,没有什么阻止d从在y的修改次序出现A之前和B从在修改次序出现在C之前的x。线程1中的负载A可以看到D对y的副作用,而线程2中的负载C可以看到B对x的副作用。

松散内存排序的典型用法是递增计数器,如引用计数器,因为这只需要原子性,但不需要排序或同步(注意递减shared_ptr计数器需要与析构函数进行获取释放同步)。

发布 - 消费订购

如果线程A中的原子存储被标记memory_order_release并且来自同一变量的线程B中的原子加载被标记memory_order_consume,则所有存储器从原子存储之前写入(非原子和放宽原子)线程A 在线程B中的那些操作内成为可见的副作用,负载操作携带依赖性,即一旦原子加载完成,线程B中的那些使用从加载获得的值的运算符和函数被保证为看看写到内存的线程是什么。

同步仅在释放使用相同原子变量的线程之间建立。其他线程可以看到不同的存储器访问顺序,而不是任何一个或两个同步线程。

在DEC Alpha以外的所有主流CPU上,依赖性排序是自动的,不会为此同步模式发出额外的CPU指令,只会影响某些编译器优化(例如,禁止编译器对涉及依赖项的对象执行推测性加载链)。

这种排序的典型用例涉及读取访问很少写入的并发数据结构(路由表,配置,安全策略,防火墙规则等)以及使用指针中介发布的发布者订阅者情况,也就是说,当生产者发布指针时消费者可以访问这些信息:不需要将生产者写入内存的所有内容都写入消费者可以看到的内存中(这可能是对弱排序架构的昂贵操作)。这种情况的一个例子是rcu_dereference。

请注意,目前(2015年2月)没有已知的生产编译器跟踪依赖链:消耗操作被解除以获取操作。

Release sequence

如果一些原子被存储释放并且其他几个线程对该原子执行读 - 修改 - 写操作,则形成“release sequence”:执行读取 - 修改的所有线程 - 写入相同的原子与第一线程同步并且即使他们没有memory_order_release语义,也是如此。这使单个生产者 - 多个消费者情况成为可能,而不会在各个消费者线程之间施加不必要的同步。

发布 - 获取订购

如果线程A中的原子存储被标记memory_order_release并且来自同一变量的线程B中的原子加载被标记memory_order_acquire,则所有存储从线程A的角度在原子存储之前写入(非原子和放宽原子)在线程B中变成可见的副作用,也就是说,一旦完成了原子加载,线程B就会保证看到线程A写入内存的所有内容。

同步仅在释放获取相同原子变量的线程之间建立。其他线程可以看到不同的存储器访问顺序,而不是任何一个或两个同步线程。

在高度有序的系统(x86,SPARC TSO,IBM大型机)上,大多数操作的发布采集排序是自动的。对于此同步模式,不会发出额外的CPU指令,只会影响某些编译器优化(例如,禁止编译器将原子存储释放移出原子存储释放或在原子载入获取之前执行非原子加载)。在弱有序的系统(ARM,Itanium,PowerPC)上,必须使用特殊的CPU负载或内存防护指令。

相互排斥锁(如互斥锁或原子螺旋锁)是发布 - 获取同步的一个示例:当锁由线程A释放并由线程B获取时,上下文中关键部分(释放之前)发生的所有事件线程A必须对正在执行相同关键部分的线程B(获取之后)可见。

顺序一致的排序

原子操作memory_order_seq_cst不仅以与释放/获取顺序相同的方式标记内存(发生的所有事情 -在一个线程中的存储变成执行加载的线程中的可见副作用之前),而且还建立了所有的修改顺序原子操作如此标记。

从形式上看,

memory_order_seq_cst从原子变量M加载的每个操作B都遵循以下之一:

  • 最后一个操作A的结果是修改后的M,它出现在单个总订单中的B之前

  • 或者,如果有这样一个A,那么B可以观察到M上的一些修改的结果,memory_order_seq_cst而不是 A 之前发生并且不发生

  • 或者,如果没有这样的A,则B可以观察到M的一些不相关的修改的结果 memory_order_seq_cst

如果 B 之前有一个排序memory_order_seq_cst atomic_thread_fence操作X ,则B会观察以下之一:

  • memory_order_seq_cst在单个总订单中出现在X之前的M 的最后修改

  • M的修改顺序中稍后出现的一些与M无关的修改

对于M上的一对称为A和B的原子操作,其中A写入并且B读取M的值,如果有两个memory_order_seq_cst atomic_thread_fences X和Y,并且如果A被排序 - 在 X 之前,Y被排序 - 在 B 之前,并且X出现在单一全部订单中Y之前,则B观察到:

  • A的效果

  • M在M的修改顺序中出现在A后面的一些不相关的修改

对于称为A和B的M的一对原子修饰,B在M的修饰顺序为A之后发生。

  • 有一个memory_order_seq_cst atomic_thread_fenceX使得A被排序 - 在 X和X出现在单个全部顺序中的B之前

  • 或者,有一个memory_order_seq_cst atomic_thread_fenceY使得Y 排序 - 在 B和A之前出现在单个总排序中的Y 之前

  • 或者,存在memory_order_seq_cst atomic_thread_fenceS和X,使得A被排序 - 在 X 之前,Y B 之前排序,并且X在单个总排序中出现在Y之前。

请注意,这意味着:

1)一旦没有标记的原子操作memory_order_seq_cst进入图片,就会失去顺序一致性

2)顺序一致的栅栏只为栅栏本身建立总排序,而不是针对一般情况下的原子操作(顺序 - 之前不是跨线程关系,不像以前发生的那样)

对于多个生产者 - 多个消费者情况,序列排序可能是必要的,其中所有消费者都必须遵守以相同顺序出现的所有生产者的行为。

全部顺序排序需要在所有多核系统上提供完整的内存围栏CPU指令。这可能会成为性能瓶颈,因为它会迫使受影响的内存访问传播到每个内核。

与volatile关系

在一个执行线程中,通过易变的左值访问(读写)不能重新排序超过由相同线程中的序列点分隔的可观察副作用(包括其他易失性访问),但不保证此顺序被观察到由另一个线程,因为易失性访问不建立线程间同步。

此外,易失性访问不是原子性的(并发读写是数据竞争),也不会对内存进行排序(非易失性内存访问可以在易失性访问周围自由重新排序)。

一个值得注意的例外是Visual Studio,其中默认设置下,每个易失性写入都具有释放语义,每个易失性读取都获取语义(MSDN,因此挥发性可用于线程间同步,标准volatile语义不适用于多线程编程,尽管它们足以用于与signal应用于sig_atomic_t变量时在同一线程中运行的处理程序进行通信。

示例

参考

  • C11标准(ISO/IEC 9899:2011):

    • 7.17.1/4 memory_order(p: 273)

    • 7.17.3订单和一致性(p: 275-277)

另请参阅

| 用于记忆顺序的C ++文档|

上一篇: 下一篇: