日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C11标准委员会成员解读C语言新标准

發布時間:2023/12/18 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C11标准委员会成员解读C语言新标准 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

導讀:C語言國際標準新的新草案之前已經公布,新標準提高了對C++的兼容性,并將新的特性增加到C語言中。此外支持多線程的功能也受到了開發者的關注,基于ISO/IEC TR 19769:2004規范下支持Unicode,提供更多用于查詢浮點數類型特性的宏定義和靜態聲明功能。根據草案規定,最新發布的標準草案修訂了許多特性,支持當前的編譯器。(背景:C編程語言的標準化委員會(ISO/IEC JTC1/SC22/WG14)已完成了C標準的主要修訂,該標準的早期版本于1999年完成,俗稱為“C99”。新標準在去年年底完成,也被稱為“C11”。)

本文作者Tom Plum是Plum Hall Inc.的技術工程副總監,也是C11和C++11標準委員會的成員,他在這篇文章里從語言集的atomic操作和線程原語開始探討了C語言的新特性,在文章末尾還討論了C11與C++兼容性問題。此外,在本文和它的姊妹篇里,作者還描述了C11的新功能、并發性、安全性和易用性等話題。

并發

C11的標準化了可能運行在多核平臺上的多線程程序的語義,使用atomic變量讓線程間通信更輕量。

頭文件<threads.h>提供宏、類型以及支持多線程的函數。下面是宏、類型和枚舉常量的摘要總結:

??? 宏:

  • thread_local,?ONCE_FLAG,?TSS_DTOR_ITERATIONS?cnd_t?thrd_t,?tss_t,?mtx_t,?tss_dtor_t,?thrd_start_t,?once_flag。?
  • ??? 通過枚舉常量:

  • mtx_init:?mtx_plain,?mtx_recursive,?mtx_timed。?
  • ??? 線程枚舉常量:

  • thrd_timedout,?thrd_success,?thrd_busy,?thrd_error,?thrd_nomem。?
  • ??? 條件變量的函數:

  • call_once(once_flag?*flag,?void?(*func)(void));?
  • cnd_broadcast(cnd_t?*cond);?
  • cnd_destroy(cnd_t?*cond);?
  • cnd_init(cnd_t?*cond);?
  • cnd_signal(cnd_t?*cond);?
  • cnd_timedwait(cnd_t?*restrict?cond,?mtx_t?*restrict?mtx,?const?struct?timespec?*restrict?ts);?
  • cnd_wait(cnd_t?*cond,?mtx_t?*mtx);?
  • ??? 互斥函數:

  • void?mtx_destroy(mtx_t?*mtx);?
  • int?mtx_init(mtx_t?*mtx,?int?type);?
  • int?mtx_lock(mtx_t?*mtx);?
  • int?mtx_timedlock(mtx_t?*restrict?mtx;?
  • const?struct?timespec?*restrict?ts);?
  • int?mtx_trylock(mtx_t?*mtx);?
  • int?mtx_unlock(mtx_t?*mtx);?
  • ??? 線程函數:

  • int?thrd_create(thrd_t?*thr,?thrd_start_t?func,?void?*arg);?
  • thrd_t?thrd_current(void);?
  • int?thrd_detach(thrd_t?thr);?
  • int?thrd_equal(thrd_t?thr0,?thrd_t?thr1);?
  • noreturn?void?thrd_exit(int?res);?
  • int?thrd_join(thrd_t?thr,?int?*res);?
  • int?thrd_sleep(const?struct?timespec?*duration,?struct?timespec?*remaining);?
  • void?thrd_yield(void);?
  • ??? 特定于線程的存儲功能:

  • int?tss_create(tss_t?*key,?tss_dtor_t?dtor);?
  • void?tss_delete(tss_t?key);?
  • void?*tss_get(tss_t?key);?
  • int?tss_set(tss_t?key,?void?*val);?
  • 這些標準庫函數可能更適合作為易用的API的基礎而不是開發平臺來使用。例如,使用這些低級庫的函數時,很容易造成數據競爭,多個進程會不同步地對同一個位置的數據進行操作。C(和C++)標準允許任何行為,即使會發生爭用同一個變量x,哪怕會導致嚴重的后果。例如,多字節值x可能被一個線程修改部分字節,而另一個線程又會修改別的部分(值撕裂),或者產生一些其它的副作用。

    下面一個簡單的示例程序,它包含一個數據競爭,其中64位的整數x會同時被兩個線程改動。

  • #include?<threads.h>?
  • #include?<stdio.h>?
  • #define?N?100000?
  • char?buf1[N][99]={0},?buf2[N][99]={0};?
  • long?long?old1,?old2,?limit=N;?
  • long?long?x?=?0;?
  • ??
  • static?void?do1()??{?
  • ???long?long?o1,?o2,?n1;?
  • ???for?(long?long?i1?=?1;?i1?<?limit;?++i1)?{?
  • ??????old1?=?x,?x?=?i1;?
  • ??????o1?=?old1;??o2?=?old2;?
  • ??????if?(o1?>?0)?{?//?x?was?set?by?this?thread?
  • ?????????if?(o1?!=?i1-1)?
  • ????????????sprintf(buf1[i1],?"thread?1:?o1=%7lld,?i1=%7lld,?o2=%7lld",?
  • ?????????????????????o1,?i1,?o2);?
  • ??????}?else?{??????//?x?was?set?by?the?other?thread?
  • ?????????n1?=?x,?x?=?i1;?
  • ?????????if?(n1?<?0?&&?n1?>?o1)?
  • ????????????sprintf(buf1[i1],?"thread?1:?o1=%7lld,?i1=%7lld,?n1=%7lld",?
  • ?????????????????????o1,?i1,?n1);?
  • ??????}?????????
  • ???}?
  • }?
  • ??
  • static?void?do2()??{?
  • ???long?long?o1,?o2,?n2;?
  • ???for?(long?long?i2?=?-1;?i2?>?-limit;?--i2)?{?
  • ??????old2?=?x,?x?=?i2;?
  • ??????o1?=?old1;?o2?=?old2;?
  • ??????if?(o2?<?0)?{?//?x?was?set?by?this?thread?
  • ?????????if?(o2?!=?i2+1)?
  • ????????????sprintf(buf2[-i2],?"thread?2:?o2=%7lld,?i2=%7lld,?o1=%7lld",?
  • ?????????????????????o2,?i2,?o1);?
  • ??????}?else?{??????//?x?was?set?by?the?other?thread?
  • ?????????n2?=?x,?x?=?i2;?
  • ?????????if?(n2?>?0?&&?n2?<?o2)?
  • ????????????sprintf(buf2[-i2],?"thread?2:?o2=%7lld,?i2=%7lld,?n2=%7lld",?
  • ?????????????????????o2,?i2,?n2);?
  • ??????}?
  • ???}?
  • }?
  • ??
  • int?main(int?argc,?char?*argv[])?
  • {?
  • ???thrd_t?thr1;?
  • ???thrd_t?thr2;?
  • ???thrd_create(&thr1,?do1,?0);?
  • ???thrd_create(&thr2,?do2,?0);?
  • ???thrd_join(&thr2,?0);?
  • ???thrd_join(&thr1,?0);?
  • ???for?(long?long?i?=?0;?i?<?limit;?++i)?{?
  • ??????if?(buf1[i][0]?!=?'\0')?
  • ?????????printf("%s\n",?buf1[i]);?
  • ??????if?(buf2[i][0]?!=?'\0')?
  • ?????????printf("%s\n",?buf2[i]);?
  • ???}?
  • ???return?0;?
  • }??
  • 如果你的應用已經符合C11的標準,并且將它在一個32位的機器編譯過了(在64位機器里long long類型會占用兩倍以上的存儲周期),你將會看到數據競爭的結果,得到像下面亂碼一樣的輸出:

  • thread?2:?o2=-4294947504,?i2=????-21,?o1=??19792?
  • 傳統的解決方案是通過創建一個鎖來解決數據競爭。然而,用atomic數據有時會更高效。加載和存儲atomic類型循序漸進、始終如一。特別是如果線程1存儲了一個值名為x的atomic類型變量,線程2讀取該值時則可以看到之前在線程1中運行的所有其它存儲(即使是非atomic對象)。(C11和C++11標準還提供其他內存一致性的模型,雖然專家提醒要遠離它們。)

    新的頭文件<stdatomic.h>提供了很多命名類和函數來操作atomic數據的大集。例如,atomic_llong就是一個為操作atomic long long整數的類型。所有的整數類都提供了相似的命名。該標準包括一個ATOMIC_VAR_INIT(n)宏,用來初始化atomic整數,如下:

    之前的數據競爭的例子可以通過定義x為一個atomic_llong類型的變量解決。簡單地改變一下上述例子中聲明x的那行語句:

  • #include?<stdatomic.h>?
  • atomic_llong?x?=?ATOMIC_VAR_INIT(0);?
  • 通過使用這樣的atomic變量,代碼在運行中不會出現任何數據競爭的問題。

    注意關鍵字

    C委員會并不希望在用戶命名空間里創建新的關鍵字,每個新的C版本都一直在避免出現不兼容之前版本C程序的問題。相比之下,C++委員會(WG21)更喜歡創造新的關鍵字,例如:C++11定義一個新的thread_local關鍵字來指定一個線程的本地靜態存儲,C11使用_Thread_local來代替,在C11新的頭文件<threads.h>中有一個宏定義來提供normal-looking name:

  • #define???thread_local????_Thread_local?
  • 下面我將假設你已經引入例如適當的頭文件,所以我會顯示normal-looking name。

    thread_local存儲類

    新thread_local存儲類為每個線程提供一個單獨的靜態存儲,并且在線程運行之前初始化。但有沒有保障措施來防止你捕獲一個thread_local變量的地址,并把它傳遞給其他線程,然后明確實現(即,不便攜/不可移植),每個線程在thread_local都有它自己的errno存儲副本。

    線程可選

    C11已指定為多種特色為可選功能,例如:如果它明確實現了一個名為 _ _STDC_NO_THREADS_ _ 的宏,就不會提供一個頭名為<threads.h>的頭文件,也不可能在其中定義任何函數。

    設計準則

    作為通則,WG21委托Bjarne Stroustrup整體設計和進化的責任,不明白的話可以在網上搜索“camel is a horse designed by committee”。然而,有一個WG14和WG21同樣遵循的設計原則:不要給任何系統編程語言比我們(C/C++)更高效的機會!

    一些與會者(稱他們為“A組”)認為atomic數據仍將是一個很少使用的專業性功能,但其他人(稱他們為“B組”)認為,atomic數據將成為一個重要的功能,至少會在一種系統編程語言中被應用。

    在過去的幾十年里,很多更高級別的語言都是基于C語言創建的(Java,C#,ObjectiveC,當然,也包括C++)和C++子集或超集(如D和嵌入式C++)。許多參與WG14和WG21的公司已經決定使用這些語言作為自己的應用的編程語言(稱他們為“C組”)。這些公司之所以選擇C++作為他們的上層應用程序的語言,通常是因為C足夠穩定(或者說是因為WG21控制其標準化),而選擇其他語言的公司(稱他們為“D組”)通常認為C是他們所使用的高級語言非常重要的基石。

    有了這些背景,我可以得出一個C11中atomic進化的理由。C++11中對atomic的設計充分運用了模板。比如atomic<T>是獲得任何一種類型T的簡單且常用的方法。即使T是一個類或結構,那么無論T*指向哪兒,atomic<T*>都會保存類型信息,但是,幾年來,C語言的設計依然只用了幾十種命名類型(如上所示的atomic_llong)。這樣做的主要優點在于:它不需要編譯器做任何改變。它能夠實現一個僅庫的解決方案,會在最低水平調用系統依賴的原生函數。然而命名類型的解決方案干撓了為C結構或者T*指針創建atomic(無論多么小)。主要因為B組和D組的意見,WG14決定要求C11編譯器為任何類型的T識別atomicT。

    后來也有一個WG14內部的關于編譯器識別atomicT語法的爭論。一種使用atomic-parenthesis的解決方案因為和C++良好的兼容性而被推動。Let _Atomic(T)成為了指定atomicT的語法。同樣的源程序能夠簡單地在C++定義宏中編譯。

  • #define?_Atomic(T)????atomic<T>?
  • 另一種相反的觀點認為應該創建新的類限制符(類似于C99的_Complex的解決方案);使用"atomic-space"語法,atomic T類型應該被寫為“_Atomic T”。使用這種語法的程序型的程序無法立刻被當作C++來編譯。(無兼容性宏,本質上看起來像atomic-parenthesis的方法)。

    獲取C11標準

    新標準可以在webstore.ansi.org查看(或者搜索"ISO/IEC 9899:2011")。現在已經有了PDF文檔,但是需要支付$285(和C++2011一樣)才可以使用。一旦這些標準被ANSI采納為美國國家標準,價格將下降至$30左右。

    你可以定期檢查此頁面的部分,我及時檢查草案的狀態,如果您填寫了這個Web表單,將會在C11和C++11被ANSI采用為標準時獲得電子郵件通知。也可以通過tplum@plumhall.com聯系我,非常感謝來自Pete Becker(C++2011標準的項目編輯)的建設性建議。

    原文鏈接:drdobbs.com

    更多關于C11的變更可以參考維基百科


    相關文章:

    ISO發布C語言標準新版本

    C語言中史上最愚蠢的Bug

    如何創建比C語言更快的編程語言?

    總結

    以上是生活随笔為你收集整理的C11标准委员会成员解读C语言新标准的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。