精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

基于多線程環境下值的遞增操作--原子操作

C語言專家集中營 ? 2018-01-10 11:16 ? 次閱讀

為了描述方便和代碼簡潔起見,我們可以只輸出最后的報數結果來觀察程序是否運行出錯。這也非常類似于統計一個網站每天有多少用戶登錄,每個用戶登錄用一個線程模擬,線程運行時會將一個表示計數的變量遞增。程序在最后輸出計數的值表示有今天多少個用戶登錄,如果這個值不等于我們啟動的線程個數,那顯然說明這個程序是有問題的。整個程序代碼如下:

[cpp]view plaincopy

#include

#include

#include

volatilelongg_nLoginCount;//登錄次數

unsignedint__stdcallFun(void*pPM);//線程函數

constintTHREAD_NUM=10;//啟動線程數

unsignedint__stdcallThreadFun(void*pPM)

{

Sleep(100);//someworkshouldtodo

g_nLoginCount++;

Sleep(50);

return0;

}

intmain()

{

g_nLoginCount=0;

HANDLEhandle[THREAD_NUM];

for(inti=0;i

handle[i]=(HANDLE)_beginthreadex(NULL,0,ThreadFun,NULL,0,NULL);

WaitForMultipleObjects(THREAD_NUM,handle,TRUE,INFINITE);

printf("有%d個用戶登錄后記錄結果是%d\n",THREAD_NUM,g_nLoginCount);

return0;

}

程序中模擬的是10個用戶登錄,程序將輸出結果:

基于多線程環境下值的遞增操作--原子操作

和上一篇的線程報數程序一樣,程序輸出的結果好象并沒什么問題。下面我們增加點用戶來試試,現在模擬50個用戶登錄,為了便于觀察結果,在程序中將50個用戶登錄過程重復20次,代碼如下:

[cpp]view plaincopy

#include

#include

volatilelongg_nLoginCount;//登錄次數

unsignedint__stdcallFun(void*pPM);//線程函數

constDWORDTHREAD_NUM=50;//啟動線程數

DWORDWINAPIThreadFun(void*pPM)

{

Sleep(100);//someworkshouldtodo

g_nLoginCount++;

Sleep(50);

return0;

}

intmain()

{

printf("原子操作Interlocked系列函數的使用\n");

printf("--byMoreWindows(http://blog.csdn.net/MoreWindows)--\n\n");

//重復20次以便觀察多線程訪問同一資源時導致的沖突

intnum=20;

while(num--)

{

g_nLoginCount=0;

inti;

HANDLEhandle[THREAD_NUM];

for(i=0;i

handle[i]=CreateThread(NULL,0,ThreadFun,NULL,0,NULL);

WaitForMultipleObjects(THREAD_NUM,handle,TRUE,INFINITE);

printf("有%d個用戶登錄后記錄結果是%d\n",THREAD_NUM,g_nLoginCount);

}

return0;

}

運行結果如下圖:

基于多線程環境下值的遞增操作--原子操作

現在結果水落石出,明明有50個線程執行了g_nLoginCount++;操作,但結果輸出是不確定的,有可能為50,但也有可能小于50。

要解決這個問題,我們就分析下g_nLoginCount++;操作。在VC6.0編譯器對g_nLoginCount++;這一語句打個斷點,再按F5進入調試狀態,然后按下Debug工具欄的Disassembly按鈕,這樣就出現了匯編代碼窗口。可以發現在C/C++語言中一條簡單的自增語句其實是由三條匯編代碼組成的,如下圖所示。

基于多線程環境下值的遞增操作--原子操作

講解下這三條匯編意思:

第一條匯編將g_nLoginCount的值從內存中讀取到寄存器eax中。

第二條匯編將寄存器eax中的值與1相加,計算結果仍存入寄存器eax中。

第三條匯編將寄存器eax中的值寫回內存中。

這樣由于線程執行的并發性,很可能線程A執行到第二句時,線程B開始執行,線程B將原來的值又寫入寄存器eax中,這樣線程A所主要計算的值就被線程B修改了。這樣執行下來,結果是不可預知的——可能會出現50,可能小于50。

因此在多線程環境中對一個變量進行讀寫時,我們需要有一種方法能夠保證對一個值的遞增操作是原子操作——即不可打斷性,一個線程在執行原子操作時,其它線程必須等待它完成之后才能開始執行該原子操作。這種涉及到硬件的操作會不會很復雜了,幸運的是,Windows系統為我們提供了一些以Interlocked開頭的函數來完成這一任務(下文將這些函數稱為Interlocked系列函數)。

下面列出一些常用的Interlocked系列函數:

1.增減操作

LONG__cdeclInterlockedIncrement(LONGvolatile*Addend);

LONG__cdeclInterlockedDecrement(LONGvolatile*Addend);

返回變量執行增減操作之后的值。

LONG__cdecInterlockedExchangeAdd(LONGvolatile*Addend,LONGValue);

返回運算后的值,注意!加個負數就是減。

2.賦值操作

LONG__cdeclInterlockedExchange(LONGvolatile*Target,LONGValue);

Value就是新值,函數會返回原先的值。

在本例中只要使用InterlockedIncrement()函數就可以了。將線程函數代碼改成:

[cpp]view plaincopy

DWORDWINAPIThreadFun(void*pPM)

{

Sleep(100);//someworkshouldtodo

//g_nLoginCount++;

InterlockedIncrement((LPLONG)&g_nLoginCount);

Sleep(50);

return0;

}

再次運行,可以發現結果會是唯一的。

基于多線程環境下值的遞增操作--原子操作

因此,在多線程環境下,我們對變量的自增自減這些簡單的語句也要慎重思考,防止多個線程導致的數據訪問出錯。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 多線程
    +關注

    關注

    0

    文章

    277

    瀏覽量

    19923
  • C++
    C++
    +關注

    關注

    22

    文章

    2104

    瀏覽量

    73503
  • 遞增
    +關注

    關注

    0

    文章

    3

    瀏覽量

    6678

原文標題:原子操作 Interlocked系列函數

文章出處:【微信號:C_Expert,微信公眾號:C語言專家集中營】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    一文詳解RTOS開發中的原子操作

    裸機開發與RTOS開發一個非常重要的區別在于多線程之間的消息傳遞和數據共享問題,然而在這中間變量的原子操作是一個非常重要的話題,不同的處理器架構和編譯選項都可能生成不同的指令,從而影響到變量的
    發表于 11-17 09:43 ?1687次閱讀

    Java多線程的用法

    本文將介紹一Java多線程的用法。 基礎介紹 什么是多線程 指的是在一個進程中同時運行多個線程,每個線程都可以獨立執行不同的任務或
    的頭像 發表于 09-30 17:07 ?930次閱讀

    LabView的多線程語言

    LabView的多線程語言以前只會照貓畫虎的寫一些簡單的程序,一些基本原理不是很清晰。從網上找了一些資料,這里總結一。1。一般情況,運行一個 VI,至少有兩個線程:一個界面
    發表于 06-08 10:13

    原子操作指令的作用

    一些常用操作原子指令,這些原子指令的作用就是避免多線程同時對一個共享數據進行讀寫操作。沒有原子
    發表于 09-18 21:39

    Java操作系統支持多線程

    Windows等操作系統均支持多線程進程的并發處理機制。操作系統支持多線程,使多個程序能夠并發執行,以改善資源使用率和提高系統效率;操作系統
    發表于 08-05 06:06

    基于51單片機的多線程操作系統 精選資料分享

    我知道,在51單片機上運行一個操作系統,大多數情況并不實用。但51單片機廣為人知。所以我認為,用它來逐步的實現一個多線程操作系統,使得讀者以更多的精力思考
    發表于 07-20 07:55

    如何使用多線程和異步操作等并發設計方法來最大化程序的性能

    (超線程、雙核)的普及,多線程和異步操作等并發程序設計方法也受到了更多的關注和討論。本文主要是想探討一如何使用并發來最大化程序的性能。  多線程
    發表于 08-23 16:31

    在MCU開發中使用多線程操作一寫一讀是否需要保護?

    ,那么多線程訪問是安全的,那么對于一寫一讀,在某些情況需要保護,某些情況其實可以不需要保護。當操作數據是 1字節 uint8_t 類型數據,可以不做保護,對于uint8_t類型的數
    發表于 02-01 15:42

    QNX環境多線程編程

    介紹了QNX 實時操作系統和多線程編程技術,包括線程間同步的方法、多線程程序的分析步驟、線程基本程序結構以及實用編譯方法。QNX 是由加拿大
    發表于 08-12 17:37 ?30次下載

    MFC多線程編程

    計算機上的上位機制作工具語言之MFC多線程編程
    發表于 09-01 14:55 ?0次下載

    linux多線程編程技術

    1 引言 線程(thread)技術早在60年代就被提出,但真正應用多線程操作系統中去,是在80年代中期,solaris是這方面的佼佼者。傳統的 Unix也支持線程的概念,但是在一個進
    發表于 10-24 16:01 ?5次下載

    Linux多線程編程

    線程呢?使用多線程到底有哪些好處?什么的系統應該選用多線程?我們首先必須回答這些問題。  使用多線程的理由之一是和進程相比,它是一種非常"節儉"的多任務
    發表于 04-02 14:43 ?596次閱讀

    多線程的情況如何對一個進行 a++ 操作

    多線程的情況,對一個進行 a++ 操作,會出現什么問題? a++ 的問題 先寫個 demo 的例子。把 a++ 放入多線程中運行一
    的頭像 發表于 10-13 11:17 ?658次閱讀
    在<b class='flag-5'>多線程</b>的情況<b class='flag-5'>下</b>如何對一個<b class='flag-5'>值</b>進行 a++ <b class='flag-5'>操作</b>

    多線程如何保證數據的同步

    。本文將詳細介紹多線程數據同步的概念、問題、以及常見的解決方案。 一、多線程數據同步概念 在多線程編程中,數據同步指的是通過某種機制來確保多個線程對共享數據的
    的頭像 發表于 11-17 14:22 ?1163次閱讀

    redis使用多線程處理操作命令

    討 Redis 多線程處理操作命令的實現和優勢,幫助讀者深入了解這一方面的知識。 首先,我們來了解一 Redis 的基本概念和工作原理。Redis 是一個支持鍵值對存儲的數據庫系統,它將數據存儲在內存中,從而實現了高速讀寫
    的頭像 發表于 12-05 10:25 ?545次閱讀