目录搜索
AlgorithmsAlgorithms(算法)bsearchbsearch_sqsortqsort_sAtomic operationsAtomic operations library(原子操作库)ATOMIC_*_LOCK_FREEatomic_compare_exchange_strongatomic_compare_exchange_strong_explicitatomic_compare_exchange_weakatomic_compare_exchange_weak_explicitatomic_exchangeatomic_exchange_explicitatomic_fetch_addatomic_fetch_add_explicitatomic_fetch_andatomic_fetch_and_explicitatomic_fetch_oratomic_fetch_or_explicitatomic_fetch_subatomic_fetch_sub_explicitatomic_fetch_xoratomic_fetch_xor_explicitatomic_flagatomic_flag_clearatomic_flag_clear_explicitATOMIC_FLAG_INITatomic_flag_test_and_setatomic_flag_test_and_set_explicitatomic_initatomic_is_lock_freeatomic_loadatomic_load_explicitatomic_signal_fenceatomic_storeatomic_store_explicitatomic_thread_fence(线程围栏)ATOMIC_VAR_INITkill_dependencymemory_order(内存排序)C keywordsauto(自动存储)break(跳出循环)C keywords(关键词)casecharconst(常量修饰符)continuedefault(预设运算式)dodouble(双精度浮点型)elseenum(枚举类型)extern(全局变量)float(浮点数)forfortrangoto(goto语句)if(if语句)inline(行内函式)intlong(长整型)register(寄存器变量)restrict( restrict类型限定符)returnshortsignedsizeof(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_localC language#define directive#elif directive#else directive#endif directive#error directive#if directive#ifdef directive#ifndef directive#include directive#line directive#pragma directivealignas(对齐指定符)Alternative operators and tokens(替代运算符和令牌)AnalyzabilityArithmetic operatorsArithmetic typesArray declaration(数组声明)Array initialization(阵列初始化)ASCII ChartAssignment operators(赋值运算符)types(atomic类型限定符)Basic conceptsBit fields(位域)break statementC languageC Operator Precedencecast operatorcharacter constant(字符字面量)Comments(注释符)Comparison operators(比较运算符)compound literals(符合字面量)Conditional inclusion(条件包含)Conformance(一致性)const type qualifier(const 限定符)Constant expressions(常量表达)continue statementDeclarations(声明)do-while loopEnumerations(枚举类型)Escape sequences(转义字符)Expressions(表达式)External and tentative definitions(外部和暂定的定义)File scope(文件范围)floating constant(浮点常量)for loopFunction declarations(函数声明)Function definitions(函数声明)FunctionsGeneric selection泛型选择goto statementIdentifier(标示符)if statementImplicit conversions(隐式转换)Increment/decrement operators(前置/后置操作符)Initialization(初始化)inline function specifier(内联函式)integer constantLifetime(生命期)Logical operators(逻辑运算符)Lookup and name spacesMain function(主函式)Member access operators(会员接入运营商)Memory modelObjects and alignment(字节对齐)Order of evaluation(评估顺序)Other operatorsPhases of translation(翻译阶段)Pointer declarationPreprocessor(预处理)restrict type qualifier(restrict类型限定符)return statementScalar initialization(标量类型初始化)Scope(范围)sizeof operator(sizeof运算符)Statements(陈述)static assert declaration(静态断言声明)Static storage duration(静态存储周期)Storage-class specifiers(存储类说明符)string literals(字符串字面量)Struct and union initialization(结构体与联合体初始化)Struct declaration(结构体声明)switch statementThread storage duration(线程存储时间)TypeType(类型)Typedef declaration(Typedef声明)Undefined behavior(未定义行为)Union declaration(联合体声明)Value categories(值类别)Variadic arguments(变长参数宏)volatile type qualifier(volatile 类型限定符)while loop_Alignof operator_Noreturn function specifierDate and timeasctime(asctime函数)asctime_sclockCLOCKS_PER_SECclock_tctime(ctime函数)ctime_sDate and time utilities(日期和时间库)difftime(计算两个时间的间隔)gmtimegmtime_slocaltimelocaltime_smktime(将时间结构数据转换成经过的秒数的函数)strftime(格式化输出时间函数)timetimespectimespec_gettime_ttmwcsftime(格式化时间宽字符)Dynamic memory managementaligned_allocC memory management library(内存管理库)callocfree(释放动态分配空间的函数)malloc(动态分配内存空间的函数)realloc(重新分配内存空间的函数)Error handlingabort_handler_sassert(断言)constraint_handler_terrno(错误报告)Error handling(错误处理)Error numbers(错误个数)ignore_handler_sset_constraint_handler_sstatic_assertFile input/outputclearerr(清除/复位)fclosefeofferrorfflush(清空文件缓冲区)fgetcfgetposfgetsfgetwcfgetwsFile input/outputfopenfopen_sfprintffprintf_sfputcfputsfputwcfputwsfreadfreopenfreopen_sfscanffscanf_sfseekfsetposftellfwidefwprintffwprintf_sfwritefwscanffwscanf_sgetcgetchargetsgets_sgetwcharperrorprintfprintf_sputcputcharputsputwcputwcharremoverenamerewindscanfscanf_ssetbufsetvbufsnprintfsprintfsscanfsscanf_sswprintfswprintf_sswscanfswscanf_stmpfiletmpfile_stmpnamtmpnam_sungetcungetwcvfprintfvfprintf_svfscanfvfscanf_svfwprintfvfwprintf_svfwscanfvfwscanf_svprintfvprintf_svscanfvscanf_svsnprintfvsprintfvsscanfvsscanf_svswprintfvswprintf_svswscanfvswscanf_svwprintfvwprintf_svwscanfvwscanf_swprintfwprintf_swscanfwscanf_sLocalization supportlconvLC_ALLLC_COLLATELC_CTYPELC_MONETARYLC_NUMERICLC_TIMElocaleconvLocalization supportsetlocaleNumericsabsacosacosfacoshacoshfacoshlacoslasinasinfasinhasinhfasinhlasinlatanatan2atan2fatan2latanfatanhatanhfatanhlatanlcabscabsfcabslcacoscacosfcacoshcacoshfcacoshlcacoslcargcargfcarglcasincasinfcasinhcasinhfcasinhlcasinlcatancatanfcatanhcatanhfcatanhlcatanlcbrtcbrtfcbrtlccosccosfccoshccoshfccoshlccoslceilceilfceillcexpcexpfcexplcimagcimagfcimaglclogclogfcloglCMPLXCMPLXFCMPLXLCommon mathematical functionscomplexComplex number arithmeticconjconjfconjlcopysigncopysignfcopysignlcoscosfcoshcoshfcoshlcoslcpowcpowfcpowlcprojcprojfcprojlcrealcrealfcreallcsincsinfcsinhcsinhfcsinhlcsinlcsqrtcsqrtfcsqrtlctanctanfctanhctanhfctanhlctanldivdouble_terferfcerfcferfclerfferflexpexp2exp2fexp2lexpfexplexpm1expm1fexpm1lfabsfabsffabslfdimfeclearexceptfegetenvfegetexceptflagfegetroundfeholdexceptferaiseexceptfesetenvfesetexceptflagfesetroundfetestexceptfeupdateenvFE_ALL_EXCEPTFE_DFL_ENVFE_DIVBYZEROFE_DOWNWARDFE_INEXACTFE_INVALIDFE_OVERFLOWFE_TONEARESTFE_TOWARDZEROFE_UNDERFLOWFE_UPWARDFloating-point environmentfloat_tfloorfloorffloorlfmafmaffmalfmaxfmaxffmaxlfminfminffminlfmodfmodffmodlfpclassifyFP_INFINITEFP_NANFP_NORMALFP_SUBNORMALFP_ZEROfrexpfrexpffrexplHUGE_VALHUGE_VALFHUGE_VALLhypothypotfhypotlIilogbilogbfilogblimaginaryimaxabsimaxdivINFINITYisfiniteisgreaterisgreaterequalisinfislessislessequalislessgreaterisnanisnormalisunorderedlabsldexpldexpfldexplldivlgammalgammaflgammalllabslldivllrintllrintfllrintlllroundllroundfllroundlloglog10log10flog10llog1plog1pflog1pllog2log2flog2llogblogbflogbllogflogllrintlrintflrintllroundlroundflroundlMATH_ERREXCEPTmath_errhandlingMATH_ERRNOmodfmodffmodflnanNANnanfnanlnearbyintnearbyintfnearbyintlnextafternextafterfnextafterlnexttowardnexttowardfnexttowardlNumericspowpowfpowlPseudo-random number generationrandRAND_MAXremainderremainderfremainderlremquoremquofremquolrintrintfrintlroundroundfroundlscalblnscalblnfscalblnlscalbnscalbnfscalbnlsignbitsinsinfsinhsinhfsinhlsinlsqrtsqrtfsqrtlsrandtantanftanhtanhftanhltanltgammatgammaftgammaltrunctruncftrunclType-generic math_Complex_I_Imaginary_IProgram supportabortatexitat_quick_exitexitEXIT_FAILUREEXIT_SUCCESSgetenvgetenv_sjmp_buflongjmpProgram support utilitiesquick_exitraisesetjmpSIGABRTSIGFPESIGILLSIGINTsignalSIGSEGVSIGTERMsig_atomic_tSIG_DFLSIG_ERRSIG_IGNsystem_ExitStringsatofatoiatolatollbtowcc16rtombc32rtombchar16_tchar32_tisalnumisalphaisblankiscntrlisdigitisgraphislowerisprintispunctisspaceisupperiswalnumiswalphaiswblankiswcntrliswctypeiswdigitiswgraphiswloweriswprintiswpunctiswspaceiswupperiswxdigitisxdigitmblenmbrlenmbrtoc16mbrtoc32mbrtowcmbsinitmbsrtowcsmbsrtowcs_smbstate_tmbstowcsmbstowcs_smbtowcmemchrmemcmpmemcpymemcpy_smemmovememmove_smemsetmemset_sNull-terminated byte stringsNull-terminated multibyte stringsNull-terminated wide stringsstrcatstrcat_sstrchrstrcmpstrcollstrcpystrcpy_sstrcspnstrerrorstrerrorlen_sstrerror_sStrings librarystrlenstrncatThread supportcall_oncecnd_broadcastcnd_destroycnd_initcnd_signalcnd_timedwaitcnd_waitmtx_destroymtx_initmtx_lockmtx_plainmtx_recursivemtx_timedmtx_timedlockmtx_trylockmtx_unlockonce_flagONCE_FLAG_INITthrd_busythrd_createthrd_currentthrd_detachthrd_equalthrd_errorthrd_exitthrd_jointhrd_nomemthrd_sleepthrd_successthrd_timedoutthrd_yieldThread support librarythread_localtss_createtss_deleteTSS_DTOR_ITERATIONStss_gettss_setType supportBoolean type support libraryFixed width integer typesFLT_EVAL_METHODFLT_ROUNDSmax_align_tNULLNumeric limitsoffsetofptrdiff_tsize_tType supportVariadic functionsVariadic functionsva_argva_copyva_endva_listva_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 ++文档|

上一篇:下一篇: