• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Kisser Leon

            這個kisser不太冷
            posts - 100, comments - 102, trackbacks - 0, articles - 0

            多線程計算PI碰到的問題

            Posted on 2007-03-23 23:42 kk 閱讀(1943) 評論(3)  編輯 收藏 引用 所屬分類: IT

            例子如下,用于計算 PI 的值。 gIterations 是計算 PI 的迭代次數(shù), gThreadCount 是線程的個數(shù)。方法是這樣子的,把 PI 分成 gThreadCount 個段,分別讓一個線程來執(zhí)行 PI 的求值操作。求得 PI 值有兩種方法,一種是直接把各個線程每一步所求得的值加到 gSum 上去,另一種是把各個線程所求得的值加到一個與之對應(yīng)的全局變量中去。對每個線程 i ,輸出 Thread number:I aaaaaaaa ,表示線程開始執(zhí)行,輸出 Thread number:I bbbbbbb 則表示線程執(zhí)行完畢。有些地方還可以優(yōu)化的,不過這里只是為了演示多線程的問題,所以就不予關(guān)注了。恩。

            代碼如下。當(dāng)只有一個 thread 的時候,結(jié)果是 OK 的( gSum==sum==3.14159* ,用等號有點(diǎn)問題,但是結(jié)果差異在十萬分之一以內(nèi))。當(dāng)有三個 threads 的時候,問題就開始出現(xiàn)了! gSum 計算出來只有 2.* !怎么會這樣子呢?各位有興趣的話,可以運(yùn)行下面的代碼試試看。接著看下面的分析。

            #include <windows.h>

            #include <stdio.h>

            #include <time.h>

            ?

            const int gIterations = 100000000;

            const int gThreadCount = 3;

            double gSum = 0.0;

            double gPart[gThreadCount];

            ?

            DWORD WINAPI threadFunction(LPVOID pArg)

            {

            ??? int threadNum = (int)pArg;//starts from 0

            ??? printf("Thread number:%d: aaaaaaaaaaaa\n", threadNum);

            ??? for ( int i=threadNum; i<gIterations; i+=gThreadCount )

            ??? {

            ??????? double dx = (i + 0.5f) / gIterations;

            ??????? gSum += 4.0f / (1.0f + dx*dx);//cause problems here!

            ??????? gPart[threadNum] += 4.0f / (1.0f + dx*dx);

            ??? }

            ?

            ??? printf("part%d value:%.6f\n", threadNum, gPart[threadNum]/gIterations);

            ??? printf("Thread number:%d: bbbbbbbbbbbb\n", threadNum);

            ??? return 0;

            }

            ?

            int main()

            {

            ??? memset(gPart, 0.0, sizeof(gPart)/sizeof(double));//init to 0

            ?

            ??? printf("Computing value of Pi: \n");

            ??? clock_t start = clock();

            ?

            ??? HANDLE threadHandles[gThreadCount];

            ??? for ( int i=0; i<gThreadCount; i++ )

            ??? {

            ??????? threadHandles[i] = CreateThread( NULL,?????????? // Security attributes

            ??????? ???????????????????????????????? 0,????????????? // Stack size

            ??????? ???????????????????????????????? threadFunction, // Thread function

            ??????? ??? ?????????????????????????????(LPVOID)i, // Data for thread func()

            ??????? ???????????????????????????????? 0,????????????? // Thread start mode

            ??????? ???????????????????????????????? NULL);????????? // Returned thread ID

            ??? }

            ?

            ??? WaitForMultipleObjects(gThreadCount, threadHandles, TRUE, INFINITE);

            ?

            ??? clock_t finish = clock();

            ??? printf("Executing time:%d\n", finish-start);

            ?

            ??? printf("global: %f\n", gSum / gIterations);

            ?

            ??? double sum = 0.0;

            ??? for(int i=0; i<gThreadCount; i++)

            ??????? sum += gPart[i];

            ??? printf("parts: %f\n", sum / gIterations);

            ?

            ??? return 0;

            }

            ?

            輸出信息:

            Computing value of Pi:

            Thread number:1: aaaaaaaaaaaa

            Thread number:0: aaaaaaaaaaaa

            Thread number:2: aaaaaaaaaaaa

            part1 value:1.047198

            Thread number:1: bbbbbbbbbbbb

            part0 value:1.047198

            Thread number:0: bbbbbbbbbbbb

            part2 value:1.047198

            Thread number:2: bbbbbbbbbbbb

            Executing time:19109

            global: 2.711738

            parts: 3.141593

            Press any key to continue

            以上是輸出信息通過 gSum 求出來的值在 2.7 左右,事實(shí)上有的時候還會更低。 WHY ?問題出現(xiàn)在哪里呢?通過各個線程計算出來的值是對的,說明問題不是出現(xiàn)在這里,也就是說問題是出現(xiàn)在線程切換的時候使得 gSum 少加了一些值!什么時候切換會導(dǎo)致這個問題呢?問題出現(xiàn)在下面這一句里面:

            ??????? gSum += 4.0f / (1.0f + dx*dx);//cause problems here!

            這一行等價于:

            ?????????????????? gSum = gSum + value;

            這一行代碼相當(dāng)于兩行代碼:

            ???????? temp = gSum + value;

            ???????? gSum = temp;

            如果有兩個線程的話:

            線程 A:

            1、 ???????????? temp = gSum + value;

            2、 ???????????? gSum = temp;

            線程 B:

            3、 ???????????? temp = gSum + value;

            4、 ???????????? gSum = temp;

            由于線程切換的任意性,這幾條指令的執(zhí)行順序有以下幾種可能:

            1 2 3 4 1 3 2 4 1 3 4 2 3 1 2 4 3 1 4 2 3 4 1 2

            其中 1 3 2 4 順序就是會出錯的,很顯然按照 1 3 2 4 順序的時候 1 中的 value 就沒有被加進(jìn)來了。這就是問題所在!同樣 1 3 4 2 3 1 2 4 3 1 4 2 都是有問題。

            那如何解決這個問題呢?要把 1 2 捆綁在一起作為一個單位操作,即所謂原子操作,要么不執(zhí)行,要么就全都執(zhí)行了。

            正確的代碼如下。給 gSum+= 操作放到一個 critical section 中,保證此時不會被線程切換干擾。關(guān)于 critical section 的詳細(xì)信息請參考 MSDN Good luck & have fun.

            #include <windows.h>

            #include <stdio.h>

            ?

            const int gIterations = 100000;

            const int gThreadCount = 4;

            double gSum = 0.0;

            CRITICAL_SECTION gCS;

            ?

            DWORD WINAPI threadFunction(LPVOIDpArg)

            {

            ???? double partialSum = 0.0;

            ?

            ???? for ( inti=(int)pArg+1; i<gIterations; i+=gThreadCount )

            ???? {

            ???????? double dx = (i - 0.5f) / gIterations;

            ???????? partialSum += 4.0f / (1.0f + dx*dx);

            ???? }

            ?

            ???? EnterCriticalSection(&gCS);

            ???? gSum += partialSum;

            ???? LeaveCriticalSection(&gCS);

            ?

            ???? return 0;

            }

            ?

            int main ()

            {

            ???? printf("Computing value of Pi: \n");

            ?

            ???? InitializeCriticalSection(&gCS);

            ???? HANDLE threadHandles[gThreadCount];

            ???? for ( inti=0; i<gThreadCount; ++i )

            ???? {

            ???????? threadHandles[i] = CreateThread( NULL,?????????? // Security attributes

            ???????? ???????????????????????????????? 0,????????????? // Stack size

            ???????? ???????????????????????????????? threadFunction, // Thread function

            ???????? ???????????????????????????????? (LPVOID)i,????? // Data for thread func()

            ???????? ???????????????????????????????? 0,???????? ?????// Thread start mode

            ???????? ???????????????????????????????? NULL);????????? // Returned thread ID

            ???? }

            ???? WaitForMultipleObjects(gThreadCount, threadHandles,? TRUE, INFINITE);

            ???? DeleteCriticalSection(&gCS);

            ?

            ???? printf("%f\n", gSum / gIterations);

            ?

            ???? return 0;

            }

            ?

            Feedback

            # re: 多線程計算PI碰到的問題  回復(fù)  更多評論   

            2007-03-24 15:05 by 小熊
            這應(yīng)該算是由race condtion產(chǎn)生的問題吧?

            # re: 多線程計算PI碰到的問題  回復(fù)  更多評論   

            2007-03-26 21:14 by 小熊
            上面對gSum += 4.0f / (1.0f + dx*dx);//cause problems here!
            的分解有誤,正確應(yīng)該由如下這些匯編代碼組成:

            00401065 fmul qword ptr [dx]
            00401068 fadd qword ptr [__real@3ff0000000000000 (403168h)]
            0040106E fdivr qword ptr [__real@4010000000000000 (403160h)]
            00401074 fadd qword ptr [gSum (4040A8h)]
            0040107A fstp qword ptr [gSum (4040A8h)]

            而gSum += i;則被翻譯成如下這些匯編代碼:

            00401080 fild dword ptr [i]
            00401083 fadd qword ptr [gSum (4040A8h)]
            00401089 fstp qword ptr [gSum (4040A8h)]

            # re: 多線程計算PI碰到的問題  回復(fù)  更多評論   

            2007-03-30 15:27 by 小熊
            printf("Hello Thread %d\n", num);
            這一句被分解為以下匯編代碼

            00401026 mov esi,esp
            00401028 mov ecx,dword ptr [num]
            0040102B push ecx
            0040102C push offset MSVCR71D_NULL_THUNK_DATA+28h (4030CCh)
            00401031 call dword ptr [__imp__printf (40309Ch)]
            00401037 add esp,8
            0040103A cmp esi,esp
            0040103C call _RTC_CheckEsp (4011D0h)
            国内精品久久久久久野外| 国产精品青草久久久久婷婷 | 久久无码高潮喷水| 99久久中文字幕| 伊人久久成人成综合网222| 久久精品视频网| 一本色道久久HEZYO无码| 久久久久久无码国产精品中文字幕| 日产精品久久久久久久| 欧美伊人久久大香线蕉综合69| 97久久香蕉国产线看观看| 模特私拍国产精品久久| 精品视频久久久久| 久久99毛片免费观看不卡| 亚洲AV无码久久寂寞少妇| 日日狠狠久久偷偷色综合0| 99久久国产主播综合精品| 国产精品久久久久9999| 久久精品aⅴ无码中文字字幕重口| 欧美一级久久久久久久大| 久久国产V一级毛多内射| 99久久精品免费观看国产| 久久亚洲国产午夜精品理论片| 久久青青草原精品国产| 久久亚洲AV成人无码国产| 亚洲国产精品无码久久SM| 久久综合狠狠综合久久| 精品久久久久久成人AV| 99久久中文字幕| 丁香五月综合久久激情| 91亚洲国产成人久久精品| 久久综合九色综合97_久久久| 国产精品毛片久久久久久久| 久久精品人人做人人爽电影| 嫩草影院久久国产精品| 91亚洲国产成人久久精品| 国产农村妇女毛片精品久久| 久久精品视频91| 国产成人久久精品一区二区三区 | 久久丝袜精品中文字幕| 久久人人添人人爽添人人片牛牛|