{"id":5216,"date":"2025-06-11T12:58:38","date_gmt":"2025-06-11T04:58:38","guid":{"rendered":"https:\/\/www.diggoodbox.com\/blog\/?p=5216"},"modified":"2025-06-11T12:58:38","modified_gmt":"2025-06-11T04:58:38","slug":"c-%e7%ba%bf%e7%a8%8b%e5%ae%89%e5%85%a8%ef%bc%88thread-safety%ef%bc%89","status":"publish","type":"post","link":"https:\/\/www.diggoodbox.com\/blog\/?p=5216","title":{"rendered":"C++ \u7ebf\u7a0b\u5b89\u5168\uff08Thread Safety\uff09"},"content":{"rendered":"\n<p><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>\u4e2d\u6587<\/strong><\/td><td><strong>English<\/strong><\/td><\/tr><tr><td><strong>\u4e00\u3001\u7ebf\u7a0b\u5b89\u5168\u7684\u6982\u5ff5<\/strong><\/td><td><strong>1. Concept of Thread Safety<\/strong><\/td><\/tr><tr><td>\u7ebf\u7a0b\u5b89\u5168\u6307\u5728\u591a\u7ebf\u7a0b\u73af\u5883\u4e2d\uff0c\u591a\u4e2a\u7ebf\u7a0b\u8bbf\u95ee\u540c\u4e00\u8d44\u6e90\u65f6\uff0c\u4e0d\u4f1a\u5bfc\u81f4\u7ade\u6001\u6761\u4ef6\u3001\u6570\u636e\u7834\u574f\u6216\u672a\u5b9a\u4e49\u884c\u4e3a\u3002<\/td><td>Thread safety means that in a multithreaded environment, multiple threads accessing the same resource will not cause race conditions, data corruption, or undefined behavior.<\/td><\/tr><tr><td>\u7b80\u5355\u8bf4\uff0c\u5c31\u662f\u4fdd\u8bc1\u7a0b\u5e8f\u6b63\u786e\u6027\u548c\u7a33\u5b9a\u6027\uff0c\u5373\u4f7f\u591a\u7ebf\u7a0b\u540c\u65f6\u6267\u884c\u76f8\u5173\u4ee3\u7801\u3002<\/td><td>In short, it guarantees program correctness and stability even when multiple threads execute related code simultaneously.<\/td><\/tr><tr><td><\/td><td><\/td><\/tr><tr><td><strong>\u4e8c\u3001\u7ebf\u7a0b\u5b89\u5168\u7684\u7ea7\u522b<\/strong><\/td><td><strong>2. Levels of Thread Safety<\/strong><\/td><\/tr><tr><td>\u4e0d\u5b89\u5168\uff08Not thread-safe\uff09\uff1a\u591a\u7ebf\u7a0b\u540c\u65f6\u8bbf\u95ee\u4f1a\u5bfc\u81f4\u9519\u8bef\u6216\u7ade\u6001\u3002<\/td><td>Not thread-safe: concurrent access by multiple threads can cause errors or race conditions.<\/td><\/tr><tr><td>\u7ebf\u7a0b\u5b89\u5168\uff08Thread-safe\uff09\uff1a\u591a\u7ebf\u7a0b\u8bbf\u95ee\u4e0d\u4f1a\u4ea7\u751f\u7ade\u6001\uff0c\u884c\u4e3a\u6b63\u786e\u3002<\/td><td>Thread-safe: multiple threads can access safely without race conditions and behave correctly.<\/td><\/tr><tr><td>\u53ef\u91cd\u5165\uff08Reentrant\uff09\uff1a\u51fd\u6570\u53ef\u88ab\u591a\u7ebf\u7a0b\/\u4e2d\u65ad\u5b89\u5168\u8c03\u7528\uff0c\u4e0d\u4f9d\u8d56\u5171\u4eab\u72b6\u6001\u3002<\/td><td>Reentrant: functions can be safely called by multiple threads or interrupts, without relying on shared state.<\/td><\/tr><tr><td>\u7ebf\u7a0b\u5c40\u90e8\uff08Thread-local\uff09\uff1a\u6bcf\u4e2a\u7ebf\u7a0b\u62e5\u6709\u72ec\u7acb\u53d8\u91cf\u526f\u672c\uff0c\u4e92\u4e0d\u5e72\u6270\u3002<\/td><td>Thread-local: each thread has its own copy of variables, avoiding interference.<\/td><\/tr><tr><td><\/td><td><\/td><\/tr><tr><td><strong>\u4e09\u3001C++\u4e2d\u5b9e\u73b0\u7ebf\u7a0b\u5b89\u5168\u7684\u5e38\u7528\u65b9\u6cd5<\/strong><\/td><td><strong>3. Common Ways to Achieve Thread Safety in C++<\/strong><\/td><\/tr><tr><td>1. \u4e92\u65a5\u9501\uff08Mutex\uff09\uff1a\u7528std::mutex\u52a0\u9501\uff0c\u4fdd\u8bc1\u540c\u4e00\u65f6\u523b\u53ea\u6709\u4e00\u4e2a\u7ebf\u7a0b\u8bbf\u95ee\u5171\u4eab\u8d44\u6e90\u3002<\/td><td>1. Mutex: use std::mutex to lock and ensure only one thread accesses shared resource at a time.<\/td><\/tr><tr><td>\u793a\u4f8b\uff1a<\/td><td>Example:<\/td><\/tr><tr><td>&#8220;`cpp<\/td><td>&#8220;`cpp<\/td><\/tr><tr><td>std::mutex mtx;<\/td><td>std::mutex mtx;<\/td><\/tr><tr><td>int shared_data = 0;<\/td><td>int shared_data = 0;<\/td><\/tr><tr><td>void safe_increment() {<\/td><td>void safe_increment() {<\/td><\/tr><tr><td>std::lock_guardstd::mutex lock(mtx);<\/td><td>std::lock_guardstd::mutex lock(mtx);<\/td><\/tr><tr><td>++shared_data;<\/td><td>++shared_data;<\/td><\/tr><tr><td>}<\/td><td>}<\/td><\/tr><tr><td>&#8220;`<\/td><td>&#8220;`<\/td><\/tr><tr><td>2. \u8bfb\u5199\u9501\uff08Shared Mutex\uff09\uff1a\u5141\u8bb8\u591a\u4e2a\u7ebf\u7a0b\u8bfb\uff0c\u5199\u65f6\u72ec\u5360\u9501\uff0cC++17 \u63d0\u4f9bstd::shared_mutex\u3002<\/td><td>2. Shared Mutex: allows multiple readers concurrently but writer has exclusive lock, provided by C++17 as std::shared_mutex.<\/td><\/tr><tr><td>3. \u539f\u5b50\u64cd\u4f5c\uff08Atomic\uff09\uff1a\u4f7f\u7528std::atomic\u5b9e\u73b0\u65e0\u9501\u540c\u6b65\uff0c\u9002\u5408\u7b80\u5355\u7c7b\u578b\u53d8\u91cf\u3002<\/td><td>3. Atomic: use std::atomic for lock-free synchronization, suitable for simple types.<\/td><\/tr><tr><td>\u793a\u4f8b\uff1a<\/td><td>Example:<\/td><\/tr><tr><td>&#8220;`cpp<\/td><td>&#8220;`cpp<\/td><\/tr><tr><td>std::atomic&lt;int&gt; count(0);<\/td><td>std::atomic&lt;int&gt; count(0);<\/td><\/tr><tr><td>void increment() {<\/td><td>void increment() {<\/td><\/tr><tr><td>count.fetch_add(1, std::memory_order_relaxed);<\/td><td>count.fetch_add(1, std::memory_order_relaxed);<\/td><\/tr><tr><td>}<\/td><td>}<\/td><\/tr><tr><td>&#8220;`<\/td><td>&#8220;`<\/td><\/tr><tr><td>4. \u7ebf\u7a0b\u5c40\u90e8\u5b58\u50a8\uff08Thread Local\uff09\uff1a\u7528thread_local\u5173\u952e\u5b57\u4e3a\u6bcf\u7ebf\u7a0b\u5206\u914d\u72ec\u7acb\u53d8\u91cf\u3002<\/td><td>4. Thread Local Storage: use thread_local keyword to assign each thread independent variables.<\/td><\/tr><tr><td>5. \u4e0d\u53ef\u53d8\u6570\u636e\/\u53ea\u8bfb\u6570\u636e\uff1a\u5171\u4eab\u53ea\u8bfb\u6570\u636e\u5929\u7136\u7ebf\u7a0b\u5b89\u5168\u3002<\/td><td>5. Immutable \/ Read-only data: shared read-only data is naturally thread-safe.<\/td><\/tr><tr><td><\/td><td><\/td><\/tr><tr><td><strong>\u56db\u3001\u7ebf\u7a0b\u5b89\u5168\u7684\u76f2\u70b9\u4e0e\u9677\u9631<\/strong><\/td><td><strong>4. Pitfalls and Common Problems in Thread Safety<\/strong><\/td><\/tr><tr><td>1. \u7ade\u6001\u6761\u4ef6\uff08Race Condition\uff09\uff1a\u591a\u7ebf\u7a0b\u540c\u65f6\u4fee\u6539\u5171\u4eab\u6570\u636e\uff0c\u5bfc\u81f4\u4e0d\u53ef\u9884\u6d4b\u7ed3\u679c\u3002<\/td><td>1. Race Condition: concurrent modification causes unpredictable results.<\/td><\/tr><tr><td>\u793a\u4f8b\u89c1\u4e0b\u3002<\/td><td>See example below.<\/td><\/tr><tr><td><\/td><td><\/td><\/tr><tr><td>2. \u6b7b\u9501\uff08Deadlock\uff09\uff1a\u591a\u4e2a\u7ebf\u7a0b\u4e92\u76f8\u7b49\u5f85\u5bf9\u65b9\u6301\u6709\u7684\u9501\uff0c\u5bfc\u81f4\u7a0b\u5e8f\u5361\u6b7b\u3002<\/td><td>2. Deadlock: threads wait on each other&#8217;s locks causing indefinite blocking.<\/td><\/tr><tr><td>\u793a\u4f8b\u89c1\u4e0b\u3002<\/td><td>See example below.<\/td><\/tr><tr><td><\/td><td><\/td><\/tr><tr><td>3. \u5185\u5b58\u53ef\u89c1\u6027\uff08Memory Visibility\uff09\uff1a\u4e00\u4e2a\u7ebf\u7a0b\u4fee\u6539\u53d8\u91cf\uff0c\u53e6\u4e00\u4e2a\u7ebf\u7a0b\u53ef\u80fd\u770b\u4e0d\u5230\u6700\u65b0\u503c\u3002<\/td><td>3. Memory Visibility: changes in one thread may not be visible to another thread immediately.<\/td><\/tr><tr><td>\u793a\u4f8b\u89c1\u4e0b\u3002<\/td><td>See example below.<\/td><\/tr><tr><td><\/td><td><\/td><\/tr><tr><td>4. \u9501\u7684\u7c92\u5ea6\uff08Lock Granularity\uff09\uff1a\u9501\u8303\u56f4\u8fc7\u5927\u5bfc\u81f4\u6027\u80fd\u74f6\u9888\uff0c\u8fc7\u5c0f\u5219\u589e\u52a0\u590d\u6742\u5ea6\u3002<\/td><td>4. Lock Granularity: coarse locks cause performance bottlenecks; fine locks add complexity.<\/td><\/tr><tr><td>\u793a\u4f8b\u89c1\u4e0b\u3002<\/td><td>See example below.<\/td><\/tr><tr><td><\/td><td><\/td><\/tr><tr><td>5. \u8bfb\u5199\u4e0d\u4e00\u81f4\uff08Read-Write Inconsistency\uff09\uff1a\u8bfb\u5199\u987a\u5e8f\u672a\u540c\u6b65\u5bfc\u81f4\u6570\u636e\u9519\u8bef\u3002<\/td><td>5. Read-Write Inconsistency: unsynchronized read\/write order leads to incorrect data.<\/td><\/tr><tr><td>\u793a\u4f8b\u89c1\u4e0b\u3002<\/td><td>See example below.<\/td><\/tr><tr><td><\/td><td><\/td><\/tr><tr><td><strong>\u4e94\u3001\u76f2\u70b9\u793a\u4f8b\u4ee3\u7801<\/strong><\/td><td><strong>5. Example Code for Pitfalls<\/strong><\/td><\/tr><tr><td><\/td><td><\/td><\/tr><tr><td><strong>\u7ade\u6001\u6761\u4ef6\uff08Race Condition\uff09\u793a\u4f8b\uff1a<\/strong><\/td><td><strong>Race Condition Example:<\/strong><\/td><\/tr><tr><td>&#8220;`cpp<\/td><td>&#8220;`cpp<\/td><\/tr><tr><td>int counter = 0;<\/td><td>int counter = 0;<\/td><\/tr><tr><td>void unsafe_increment() {<\/td><td>void unsafe_increment() {<\/td><\/tr><tr><td>for(int i = 0; i &lt; 1000; ++i) ++counter;<\/td><td>for(int i = 0; i &lt; 1000; ++i) ++counter;<\/td><\/tr><tr><td>}<\/td><td>}<\/td><\/tr><tr><td>int main() {<\/td><td>int main() {<\/td><\/tr><tr><td>std::thread t1(unsafe_increment);<\/td><td>std::thread t1(unsafe_increment);<\/td><\/tr><tr><td>std::thread t2(unsafe_increment);<\/td><td>std::thread t2(unsafe_increment);<\/td><\/tr><tr><td>t1.join();<\/td><td>t1.join();<\/td><\/tr><tr><td>t2.join();<\/td><td>t2.join();<\/td><\/tr><tr><td>std::cout &lt;&lt; &#8220;\u6700\u7ec8\u8ba1\u6570: &#8221; &lt;&lt; counter &lt;&lt; std::endl;<\/td><td>std::cout &lt;&lt; &#8220;Final count: &#8221; &lt;&lt; counter &lt;&lt; std::endl;<\/td><\/tr><tr><td>return 0;<\/td><td>return 0;<\/td><\/tr><tr><td>}<\/td><td>}<\/td><\/tr><tr><td>&#8220;`<\/td><td>&#8220;`<\/td><\/tr><tr><td><\/td><td><\/td><\/tr><tr><td><strong>\u6b7b\u9501\uff08Deadlock\uff09\u793a\u4f8b\uff1a<\/strong><\/td><td><strong>Deadlock Example:<\/strong><\/td><\/tr><tr><td>&#8220;`cpp<\/td><td>&#8220;`cpp<\/td><\/tr><tr><td>std::mutex mtx1, mtx2;<\/td><td>std::mutex mtx1, mtx2;<\/td><\/tr><tr><td>void threadA() {<\/td><td>void threadA() {<\/td><\/tr><tr><td>std::lock_guardstd::mutex lock1(mtx1);<\/td><td>std::lock_guardstd::mutex lock1(mtx1);<\/td><\/tr><tr><td>std::this_thread::sleep_for(std::chrono::milliseconds(100));<\/td><td>std::this_thread::sleep_for(std::chrono::milliseconds(100));<\/td><\/tr><tr><td>std::lock_guardstd::mutex lock2(mtx2);<\/td><td>std::lock_guardstd::mutex lock2(mtx2);<\/td><\/tr><tr><td>std::cout &lt;&lt; &#8220;\u7ebf\u7a0bA\u5b8c\u6210\\n&#8221;;<\/td><td>std::cout &lt;&lt; &#8220;Thread A done\\n&#8221;;<\/td><\/tr><tr><td>}<\/td><td>}<\/td><\/tr><tr><td>void threadB() {<\/td><td>void threadB() {<\/td><\/tr><tr><td>std::lock_guardstd::mutex lock2(mtx2);<\/td><td>std::lock_guardstd::mutex lock2(mtx2);<\/td><\/tr><tr><td>std::this_thread::sleep_for(std::chrono::milliseconds(100));<\/td><td>std::this_thread::sleep_for(std::chrono::milliseconds(100));<\/td><\/tr><tr><td>std::lock_guardstd::mutex lock1(mtx1);<\/td><td>std::lock_guardstd::mutex lock1(mtx1);<\/td><\/tr><tr><td>std::cout &lt;&lt; &#8220;\u7ebf\u7a0bB\u5b8c\u6210\\n&#8221;;<\/td><td>std::cout &lt;&lt; &#8220;Thread B done\\n&#8221;;<\/td><\/tr><tr><td>}<\/td><td>}<\/td><\/tr><tr><td>int main() {<\/td><td>int main() {<\/td><\/tr><tr><td>std::thread t1(threadA);<\/td><td>std::thread t1(threadA);<\/td><\/tr><tr><td>std::thread t2(threadB);<\/td><td>std::thread t2(threadB);<\/td><\/tr><tr><td>t1.join();<\/td><td>t1.join();<\/td><\/tr><tr><td>t2.join();<\/td><td>t2.join();<\/td><\/tr><tr><td>return 0;<\/td><td>return 0;<\/td><\/tr><tr><td>}<\/td><td>}<\/td><\/tr><tr><td>&#8220;`<\/td><td>&#8220;`<\/td><\/tr><tr><td><\/td><td><\/td><\/tr><tr><td><strong>\u5185\u5b58\u53ef\u89c1\u6027\uff08Memory Visibility\uff09\u793a\u4f8b\uff1a<\/strong><\/td><td><strong>Memory Visibility Example:<\/strong><\/td><\/tr><tr><td>&#8220;`cpp<\/td><td>&#8220;`cpp<\/td><\/tr><tr><td>bool ready = false;<\/td><td>bool ready = false;<\/td><\/tr><tr><td>int data = 0;<\/td><td>int data = 0;<\/td><\/tr><tr><td>void producer() {<\/td><td>void producer() {<\/td><\/tr><tr><td>data = 42;<\/td><td>data = 42;<\/td><\/tr><tr><td>ready = true;<\/td><td>ready = true;<\/td><\/tr><tr><td>}<\/td><td>}<\/td><\/tr><tr><td>void consumer() {<\/td><td>void consumer() {<\/td><\/tr><tr><td>while (!ready) {<\/td><td>while (!ready) {<\/td><\/tr><tr><td>std::this_thread::sleep_for(std::chrono::milliseconds(10));<\/td><td><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u672c\u6587\u5bf9C++\u7ebf\u7a0b\u5b89\u5168\u8fdb\u884c\u8bf4\u660e\u548c\u603b\u7ed3\uff0c\u5305\u62ec\u6982\u5ff5\u3001\u7ea7\u522b\u3001\u65b9\u6cd5\u3001\u76f2\u70b9\u548c\u9677\u9631\u548c\u793a\u4f8b\u7b49\uff0c\u5927\u5bb6\u53ef\u53c2\u7167\u5b66\u4e60\u548c\u5b9e\u8df5\u3002<\/p>\n","protected":false},"author":1,"featured_media":5194,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"colormag_page_container_layout":"default_layout","colormag_page_sidebar_layout":"default_layout","footnotes":""},"categories":[17],"tags":[20,21,23,29,22],"class_list":["post-5216","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-technology","tag-c","tag-21","tag-23","tag-29","tag-22"],"_links":{"self":[{"href":"https:\/\/www.diggoodbox.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/5216","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.diggoodbox.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.diggoodbox.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.diggoodbox.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.diggoodbox.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=5216"}],"version-history":[{"count":1,"href":"https:\/\/www.diggoodbox.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/5216\/revisions"}],"predecessor-version":[{"id":5217,"href":"https:\/\/www.diggoodbox.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/5216\/revisions\/5217"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.diggoodbox.com\/blog\/index.php?rest_route=\/wp\/v2\/media\/5194"}],"wp:attachment":[{"href":"https:\/\/www.diggoodbox.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=5216"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.diggoodbox.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=5216"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.diggoodbox.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=5216"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}