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>提供宏、類型以及支持多線程的函數。下面是宏、類型和枚舉常量的摘要總結:

??? 宏:

  1. thread_local,?ONCE_FLAG,?TSS_DTOR_ITERATIONS?cnd_t?thrd_t,?tss_t,?mtx_t,?tss_dtor_t,?thrd_start_t,?once_flag。?

??? 通過枚舉常量:

  1. mtx_init:?mtx_plain,?mtx_recursive,?mtx_timed。?

??? 線程枚舉常量:

  1. thrd_timedout,?thrd_success,?thrd_busy,?thrd_error,?thrd_nomem。?

??? 條件變量的函數:

  1. call_once(once_flag?*flag,?void?(*func)(void));?
  2. cnd_broadcast(cnd_t?*cond);?
  3. cnd_destroy(cnd_t?*cond);?
  4. cnd_init(cnd_t?*cond);?
  5. cnd_signal(cnd_t?*cond);?
  6. cnd_timedwait(cnd_t?*restrict?cond,?mtx_t?*restrict?mtx,?const?struct?timespec?*restrict?ts);?
  7. cnd_wait(cnd_t?*cond,?mtx_t?*mtx);?

??? 互斥函數:

  1. void?mtx_destroy(mtx_t?*mtx);?
  2. int?mtx_init(mtx_t?*mtx,?int?type);?
  3. int?mtx_lock(mtx_t?*mtx);?
  4. int?mtx_timedlock(mtx_t?*restrict?mtx;?
  5. const?struct?timespec?*restrict?ts);?
  6. int?mtx_trylock(mtx_t?*mtx);?
  7. int?mtx_unlock(mtx_t?*mtx);?

??? 線程函數:

  1. int?thrd_create(thrd_t?*thr,?thrd_start_t?func,?void?*arg);?
  2. thrd_t?thrd_current(void);?
  3. int?thrd_detach(thrd_t?thr);?
  4. int?thrd_equal(thrd_t?thr0,?thrd_t?thr1);?
  5. noreturn?void?thrd_exit(int?res);?
  6. int?thrd_join(thrd_t?thr,?int?*res);?
  7. int?thrd_sleep(const?struct?timespec?*duration,?struct?timespec?*remaining);?
  8. void?thrd_yield(void);?

??? 特定于線程的存儲功能:

  1. int?tss_create(tss_t?*key,?tss_dtor_t?dtor);?
  2. void?tss_delete(tss_t?key);?
  3. void?*tss_get(tss_t?key);?
  4. int?tss_set(tss_t?key,?void?*val);?

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

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

  1. #include?<threads.h>?
  2. #include?<stdio.h>?
  3. #define?N?100000?
  4. char?buf1[N][99]={0},?buf2[N][99]={0};?
  5. long?long?old1,?old2,?limit=N;?
  6. long?long?x?=?0;?
  7. ??
  8. static?void?do1()??{?
  9. ???long?long?o1,?o2,?n1;?
  10. ???for?(long?long?i1?=?1;?i1?<?limit;?++i1)?{?
  11. ??????old1?=?x,?x?=?i1;?
  12. ??????o1?=?old1;??o2?=?old2;?
  13. ??????if?(o1?>?0)?{?//?x?was?set?by?this?thread?
  14. ?????????if?(o1?!=?i1-1)?
  15. ????????????sprintf(buf1[i1],?"thread?1:?o1=%7lld,?i1=%7lld,?o2=%7lld",?
  16. ?????????????????????o1,?i1,?o2);?
  17. ??????}?else?{??????//?x?was?set?by?the?other?thread?
  18. ?????????n1?=?x,?x?=?i1;?
  19. ?????????if?(n1?<?0?&&?n1?>?o1)?
  20. ????????????sprintf(buf1[i1],?"thread?1:?o1=%7lld,?i1=%7lld,?n1=%7lld",?
  21. ?????????????????????o1,?i1,?n1);?
  22. ??????}?????????
  23. ???}?
  24. }?
  25. ??
  26. static?void?do2()??{?
  27. ???long?long?o1,?o2,?n2;?
  28. ???for?(long?long?i2?=?-1;?i2?>?-limit;?--i2)?{?
  29. ??????old2?=?x,?x?=?i2;?
  30. ??????o1?=?old1;?o2?=?old2;?
  31. ??????if?(o2?<?0)?{?//?x?was?set?by?this?thread?
  32. ?????????if?(o2?!=?i2+1)?
  33. ????????????sprintf(buf2[-i2],?"thread?2:?o2=%7lld,?i2=%7lld,?o1=%7lld",?
  34. ?????????????????????o2,?i2,?o1);?
  35. ??????}?else?{??????//?x?was?set?by?the?other?thread?
  36. ?????????n2?=?x,?x?=?i2;?
  37. ?????????if?(n2?>?0?&&?n2?<?o2)?
  38. ????????????sprintf(buf2[-i2],?"thread?2:?o2=%7lld,?i2=%7lld,?n2=%7lld",?
  39. ?????????????????????o2,?i2,?n2);?
  40. ??????}?
  41. ???}?
  42. }?
  43. ??
  44. int?main(int?argc,?char?*argv[])?
  45. {?
  46. ???thrd_t?thr1;?
  47. ???thrd_t?thr2;?
  48. ???thrd_create(&thr1,?do1,?0);?
  49. ???thrd_create(&thr2,?do2,?0);?
  50. ???thrd_join(&thr2,?0);?
  51. ???thrd_join(&thr1,?0);?
  52. ???for?(long?long?i?=?0;?i?<?limit;?++i)?{?
  53. ??????if?(buf1[i][0]?!=?'\0')?
  54. ?????????printf("%s\n",?buf1[i]);?
  55. ??????if?(buf2[i][0]?!=?'\0')?
  56. ?????????printf("%s\n",?buf2[i]);?
  57. ???}?
  58. ???return?0;?
  59. }??

如果你的應用已經符合C11的標準,并且將它在一個32位的機器編譯過了(在64位機器里long long類型會占用兩倍以上的存儲周期),你將會看到數據競爭的結果,得到像下面亂碼一樣的輸出:

  1. 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的那行語句:

  1. #include?<stdatomic.h>?
  2. 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:

  1. #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++定義宏中編譯。

  1. #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語言更快的編程語言?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/450700.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/450700.shtml
英文地址,請注明出處:http://en.pswp.cn/news/450700.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何將拷貝過來的數據 *.ibd 文件生效

1.將拷貝的數據文件 "qqq.idb"放在自己的數據庫中. 一般存放在 mysql/ data/ databasename 下 2. "qqq.idb" 改個名字-->"qqq--.idb", 主要是避免沖突&#xff01; 3.執行 create table qqq(...) 語句&#xff0c;此時除了會生成一個 qqq…

windows 下啟動zookeeper的zkServer.cmd服務閃退

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 解決方案把conf目錄下的默認zoo_sample.cfg的文件名字改成zoo.cfg 即可&#xff1a; 以上轉自&#xff1a;http://blog.csdn.net/qq4960…

設計模式常見面試真題詳解

文章目錄1. 設計模式1.1 說一說設計模式的六大原則1.2 說一下六大原則中的開閉原則1.3 手寫一個單例模式1.4 手寫一個線程安全的單例模式1.5 說一說你對工廠模式的理解1.6 簡單工廠模式和抽象工廠模式有什么區別&#xff1f;1.7 如何實現工廠模式&#xff1f;1.8 說一說你策略模…

Android內存優化之內存泄漏

內存泄漏 內存泄漏一般有以下幾種情況&#xff1a;單例、靜態變量、Handler、匿名內部類、資源使用未關閉 單例導致的內存泄漏 單例的情況主要是因為單例的生命周期比較長&#xff0c;如果引用的一些資源&#xff08;比如Context、圖片等&#xff09;沒有做特殊處理&#xff0c…

cmd - 使用curl命令的注意點

前言 最近在cmd中使用curl命令來測試rest api&#xff0c;發現有不少問題&#xff0c;這里記錄一下。 在cmd中使用curl命令的注意事項 json不能由單引號包括起來json數據里的雙引號要用反斜杠\轉義json數據里不能帶有空格如果想要在json數據里使用空格則必須用雙引號將整個json…

指針常見定義

再給出常用的C變量的定義方式&#xff1a;a) 一個整型數&#xff08;An integer&#xff09; b) 一個指向整型數的指針&#xff08;A pointer to an integer&#xff09; c) 一個指向指針的的指針&#xff0c;它指向的指針是指向一個整型數&#xff08;A pointer to a pointer …

場景應用題目常見面試真題詳解

文章目錄1. 場景應用1.1 微信紅包相關問題1.2 秒殺系統相關問題1.3 掃碼登錄流程1.4 如何實現單點登錄&#xff1f;1.5 如何設計一個本地緩存&#xff1f;1. 場景應用 1.1 微信紅包相關問題 參考答案 概況&#xff1a;2014年微信紅包使用數據庫硬抗整個流量&#xff0c;2015…

后Kubernetes時代的微服務

\本文要點\\當前微服務架構依然是最流行的分布式系統架構風格。Kubernetes和云原生運動已大規模地重新定義了應用設計和開發中的一些方面。\\t在云原生平臺上&#xff0c;服務僅具備可觀測性是不夠的。更基本的先決條件是使用檢查健康、響應信號、聲明資源消耗等手段實現微服務…

Dynamics CRM On-Premise V9安裝手記

下載地址&#xff1a; https://download.microsoft.com/download/A/D/D/ADDD6898-4EFA-46FA-80B6-6FE9A3CDED63/CRM9.0-Server-CHS-amd64.exe 安裝支持Windows 2016 及SQL Server 2016 SP2以上版本 我想安裝了All in one的&#xff0c;就想著用最新的SQLServer 2017&#xff0c…

金山網絡CEO傅盛:簡約之美

摘要&#xff1a;金山網絡CEO傅盛帶來了主題為《簡約之美》的精彩演講。他表示由于時代的變遷&#xff0c;紅海的競爭&#xff0c;項目的需求等原因&#xff0c;若想項目取得成功&#xff0c;唯有簡單才是王道&#xff0c;唯有簡單定位才能深入人心。那么&#xff0c;如何做到簡…

zookeeper安裝和使用 windows環境

簡介 前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 ZooKeeper是一個分布式的&#xff0c;開放源碼的分布式應用程序協調服務&#xff0c;是Google的Chubby一個開源的實現&#xff0c;…

計算機網絡常見面試真題詳解

文章目錄1. 計算機網絡1.1 請介紹七層網絡體系結構。1.2 請介紹五層網絡體系結構。1.3 了解網絡編程協議嗎&#xff1f;客戶端發送給服務器的請求&#xff0c;怎么確定具體的協議&#xff1f;1.4 TCP、HTTP、FTP分別屬于哪一層&#xff1f;1.5 講一下TCP/IP協議。1.6 說一說你對…

2018.09.14python學習第四天part2

流程控制之while循環 1.什么是循環&#xff1f;&#xff08;what&#xff09; 循環是指重復做某一件事 2.為何要有循環&#xff1f;&#xff08;why&#xff09; 為了讓計算機能像人一樣重復去做某一件事 3.如何使用循環&#xff1f;&#xff08;how&#xff09; #語法一&#…

git操作指令合集

1.下載完git&#xff0c;需要輸入用戶名和郵箱 git config --global user.name "Your Name" git config --global user.email "emailexample.com" 注意git config命令的--global參數&#xff0c;用了這個參數&#xff0c;表示這臺電腦上所有的GIt倉庫都會使…

C++回調函數(callback)的使用

什么是回調函數(callback) 模塊A有一個函數foo&#xff0c;它向模塊B傳遞foo的地址&#xff0c;然后在B里面發生某種事件&#xff08;event&#xff09;時&#xff0c;通過從A里面傳遞過來的foo的地址調用foo&#xff0c;通知A發生了什么事情&#xff0c;讓A作出相應反應。 那么…

Hibernate JPA中@Transient、@JsonIgnoreProperties、@JsonIgnore、@JsonFormat、@JsonSerialize等注解解釋

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1、Transient Transient表示該屬性并非一個到數據庫表的字段的映射,ORM框架將忽略該屬性&#xff1b; 如果一個屬性并非數據庫表的字段…

可愛的rem

前端開發中&#xff0c;移動端的開發可以說是舉足輕重了&#xff0c;可是又面臨著不同設備尺寸和分辨率的尷尬點。今天[2018-09-16]臺風山竹登陸廣東&#xff0c;來勢洶洶&#xff0c;外出是不可能的了&#xff0c;那就宅著寫寫這篇小文章吧...原文請戳這里-談談rem單位 超長的…

kafka直連方式消費多個topic

一個消費者組可以消費多個topic&#xff0c;以前寫過一篇一個消費者消費一個topic的&#xff0c;這次的是一個消費者組通過直連方式消費多個topic,做了小測試&#xff0c;結果是正確的&#xff0c;通過查看zookeeper的客戶端&#xff0c;zookeeper記錄了偏移量 package day04 /…

100個經典的C語言算法

100個經典的C算法 C語言的學習要從基礎開始&#xff0c;這里是100個經典的算法 題目&#xff1a;古典問題&#xff1a;有一對兔子&#xff0c;從出生后第3個月起每個月都生一對兔子&#xff0c;小兔 子長到第三個月后每個月又生一對兔子&#xff0c;假如兔子都不死&#xff0c;…

MySQL常見面試題目詳解

文章目錄1. SQL1.1 介紹一下數據庫分頁1.2 介紹一下SQL中的聚合函數1.3 表跟表是怎么關聯的&#xff1f;1.4 說一說你對外連接的了解1.5 說一說數據庫的左連接和右連接1.6 SQL中怎么將行轉成列&#xff1f;1.7 談談你對SQL注入的理解1.8 將一張表的部分數據更新到另一張表&…