由一個線程例子引發的思考(轉載)


在談這個例子之前先貼上進程與線程的內存結構,方便對線程有一個更深的理解。(如果覺得前面的介紹很煩,可以直接跳到最後看問題的分析和最終解決方法的代碼


進程的內存結構

下圖是在Linux/x86-32中典型的進程內存結構,從圖中的地址分佈可以看出,內核態佔1G空間,用戶態佔3G空間 
這裏寫圖片描述

關於進程的虛擬地址空間可以參考:http://blog.csdn.net/slvher/article/details/8831885 
更詳細的瞭解,可以查閱《深入理解計算機系統》虛擬存儲器章節和《操作系統教程–Linux實例分析》。

擁有2個線程的進程的內存空間

下圖沒有畫出內核態 
這裏寫圖片描述


可以看出線程和進程的一個明顯的區別,線程內存空間並不會獨立於創建他的進程,線程是運行在進程的地址空間中的。同一程序中的所有線程共享同一份全局內存區域,其中包括初始化數據段,未初始化數據段,以及堆內存段。


線程例子

這個程序想要實現的是: 
  計算3個線程總共循環了多少次,main_counter 是直接計算總的循環次數,counter[i] 是計算第 i 號線程循環的次數。sum 是3個線程各自循環次數的總和。所以,理論上main_counter 和 sum 值應該是相等的,因爲都是在計算總循環次數。

代碼1:

<code class="hljs cpp has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include<stdio.h></span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include<stdlib.h></span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include<sys/types.h></span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include<unistd.h></span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include<ctype.h></span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include<pthread.h></span>

<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#define MAX_THREAD  3  <span class="hljs-comment" style="box-sizing: border-box;">//線程個數</span></span>

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span>   main_counter,counter[MAX_THREAD]={<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>};

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>* thread_worker(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>*  arg)
{
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//將指針先強轉爲int* 再賦值 </span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>  thread_num = *(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>*)arg;
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//    printf("thread_id:%lu   counter[%d]\n",pthread_self(),thread_num);</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(;;)
    {
        counter[thread_num]++;    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//本線程的counter 加 1</span>
        main_counter++;
    }
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> main(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> argc,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span>* argv[])
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>                 i,rtn,ch;
    pthread_t           pthread_id[MAX_THREAD] =  {<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>};  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//存放線程</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(i=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;i<MAX_THREAD;i++)
    {
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//傳 &i </span>
        pthread_create(&pthread_id[i],NULL,thread_worker,&i);
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">do</span>
    {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span>   sum = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(i=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;i<MAX_THREAD;i++)
        {
            sum += counter[i];
            <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"No.%d: %llu\n"</span>,i,counter[i]);
        }
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%llu/%llu\n"</span>,main_counter,sum);
    }<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>((ch = getchar())!=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'q'</span>);

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li></ul>

這個程序執行後,加上主線程共有4個線程在運行,子線程執行的都是thread_worker 函數中的內容: 
這裏寫圖片描述

  在這塊,其實對於子線程共享了主線程的哪些資源,不必死記硬背。既然子線程運行的是函數中的內容,我們不妨就把子線程的運行想象成在調用函數。只是與我們平時寫的單線程的程序不同的是,thread_worker 函數被調用了3次,而且3個函數在同時被執行。main_counter 和 counter[] 數組是全局的,所以3個子線程可以直接使用和改變它們。而thread_num 是函數內的局部變量,所以線程之間互相不可見。


下來看看在這個程序中我們可能會遇到哪些問題?

問題1傳參很詭異

原因:傳參被主線程破壞

分析: 
   正像上面代碼中那樣,我們在創建線程的時候習慣於傳指針或取地址進去,即 &i :

<code class="hljs css has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">pthread_create</span>(&<span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">pthread_id</span><span class="hljs-attr_selector" style="color: rgb(0, 136, 0); box-sizing: border-box;">[i]</span>,<span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">NULL</span>,<span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">thread_worker</span>,&<span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">i</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

這時發現運行結果是這樣的: 
這裏寫圖片描述

很奇怪,0號線程和1號線程的循環次數是0,多執行幾次發現經常會有線程循環次數爲0,但是3個線程分明都被創建成功了,不可能不執行for 循環。

將代碼1 函數中的註釋去掉,我們打印一下thread_num 的值是否正常,同時打印線程ID用於區分線程: 
這裏寫圖片描述

居然沒有1號線程打印的 counter[i] ,但是打印3個thread_id 值不同,說明線程1也在運行。只是因爲 i = 1 傳入線程函數後,thread_num 卻變成了2,導致最後線程1 和 線程2 都是在對 counter[2] 執行加法操作。看來傳參過程出現了問題。

看一下參數傳遞的具體過程: 
這裏寫圖片描述

很明顯,當線程在執行thread_num的賦值操作之前很有可能因爲時間片用完將CPU控制權交給其他線程或者此時有其他線程在同時運行(多核CPU)。

當傳 &i 進去時,可能會發生以下情況: 
這裏寫圖片描述

如上圖,如果在賦值之前,主線程進行了下一次for 循環,執行 i++ ,準備創建 1 號線程時,*arg 變成了 1 。因爲 &i = arg = 0x6666,它們對應的是同一塊內存。


對了,上述代碼還有可能會出現3個線程傳過去的參數都變成0的情況,起初很不解,參數應該只會偏大不應該比真實值小啊。在谷仕濤同學的提醒下,終於找到了原因,源頭在這塊代碼:

這裏寫圖片描述

當主線程很快的執行完44~47的for循環,馬上又進入49~行的do while 循環中,並且執行了52行for 的第一次循環時,i 被賦值爲了0,此時就有可能導致thread_worker 函數中的 *arg 變爲了0,使得傳參發生異常。 
這裏寫圖片描述


解決方法

1、 值傳遞

直接傳 i 的值進入,而不是傳地址。

<code class="hljs r has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>
void* thread_worker(void*  arg)
{
    int  thread_num = (int)arg;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>
}

int main(int argc,char* argv[])
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(i=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;i<MAX_THREAD;i++)
    { 
        pthread_create(&pthread_id[i],<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>,thread_worker,(void*)i);
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li></ul>

這裏寫圖片描述

現在傳參正常了。 
但是,也許你還是有點不滿意,編譯的時候有個警告,不太想看見它:

這裏寫圖片描述

因爲編譯器雖然支持(void)轉化爲(int),但還是不推薦這樣做,所以產生了 warning 。我們還可以用其他方法。*

2、 借用數組傳參

將3次傳遞的參數分別保存爲數組的不同元素:

<code class="hljs r has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">//關鍵代碼
void* thread_worker(void*  arg)
{
    //先將void* 轉爲 int* 再賦值
    int  thread_num = *(int*)arg;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>
}

int main(int argc,char* argv[])
{
    int                 i,rtn,ch;
    pthread_t           pthread_id[MAX_THREAD] =  {<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>};  //存放線程
    //保存參數的數組
    int                 param[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>];
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(i=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;i<MAX_THREAD;i++)
    { 
        param[i] = i;
        pthread_create(&pthread_id[i],<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>,thread_worker,param+i);
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li></ul>

這個方法可以解決問題,但是不具有靈活性,如果創建了很多個線程呢,難道要有一個很大的數組麼。線程數量不確定怎麼辦,數組定爲多大才是合適的呢? 
下面我們採用第3種方法。

3、動態申請臨時內存

因爲每次申請內存返回的地址都不一樣,所以參數傳指針進去不會有問題,要記得賦值完釋放內存,避免內存泄漏。

<code class="hljs r has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>

void* thread_worker(void*  arg)
{
    //先將void* 轉爲 int* 再賦值
    int  thread_num = *(int*)arg;
    //釋放內存
    free((int*)arg);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>
}

int main(int argc,char* argv[])
{
    int                 i,rtn,ch;
    pthread_t           pthread_id[MAX_THREAD] =  {<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>};  //存放線程

    int                 *param;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(i=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;i<MAX_THREAD;i++)
    { 
        //申請內存臨時保存參數
        param = (int*)malloc(sizeof(int));
        *param = i;
        pthread_create(&pthread_id[i],<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>,thread_worker,param);
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li></ul>

這回滿意了。

問題2: main_counter < sum

原因:子線程相互競爭 main_counter ,導致不能正常執行 加 1 操作。

分析: 
  解決了問題1,我們發現還有問題,main_counter 居然不等於 sum 的值,與理論不符。這主要是由於 main_counter++ 語句並不是原子操作。 
什麼是原子操作呢? 
   通俗的將,就是線程執行某個操作的時候不能被其他線程打斷或破壞。好比說,你去食堂吃飯,剛刷了卡,結果給你的菜卻被另一個剛來的同學給端走了。

簡單的看一下執行 main_counter++ 的過程: 
這裏寫圖片描述

可能當線程 1 還沒完成加 1 操作的時候,此時,線程2 也開始執行 main_counter++(如果是單核CPU,線程 1 會暫時保存寄存器中的值,待下一個時間片到來時,恢復現場繼續操作; 如果是多核CPU,線程 1 和線程 2 可能會同時執行++) ,但是線程 2 看到的main_counter 還是 0 ,所以線程 2完成了加 1 操作後,main_counter 還是 1。雖然兩個線程各執行了一次加 1 操作,但是最終 main_counter 實際上只加了1次。這就導致main_counter 比理論值偏小。在3個線程運行的情況下,理論值最大是實際值的3倍。


解決辦法:加鎖

代碼2:

<code class="hljs cpp has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//初始化鎖</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> pthread_mutex_t    mutex = PTHREAD_MUTEX_INITIALIZER;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span>   main_counter,counter[MAX_THREAD]={<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>};

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>* thread_worker(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>*  arg)
{
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//先將void* 轉爲 int* 再賦值</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>  thread_num = *(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>*)arg;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//釋放內存</span>
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">free</span>((<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>*)arg);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(;;)
    {
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//加鎖</span>
        pthread_mutex_lock(&mutex);
        counter[thread_num]++;    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//本線程的counter 加 1</span>
        main_counter++;
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//解鎖</span>
        pthread_mutex_unlock(&mutex);
    }
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> main(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> argc,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span>* argv[])
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>                 i,rtn,ch;
    pthread_t           pthread_id[MAX_THREAD] =  {<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>};  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//存放線程</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>                 *param;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(i=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;i<MAX_THREAD;i++)
    { 
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//申請內存臨時保存參數</span>
        param = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>*)<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">malloc</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>));
        *param = i;
        pthread_create(&pthread_id[i],NULL,thread_worker,param);
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">do</span>
    {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span>   sum = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(i=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;i<MAX_THREAD;i++)
        {
            sum += counter[i];
            <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"No.%d: %llu\n"</span>,i,counter[i]);
        }
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%llu/%llu\n"</span>,main_counter,sum);
    }<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>((ch = getchar())!=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'q'</span>);

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//銷燬鎖資源</span>
    pthread_mutex_destroy(&mutex);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li></ul>

這裏寫圖片描述

看吧,sum 不再比 main_counter 大了。

但是,還是不能消停,這回發現 main_counter 居然比 sum 大了。如果是單核CPU,比如在單核雲服務器、虛擬機(VMWare、VirtualBox等)系統上運行時,可能看到main_counter = sum ,但是不代表不會出現main_counter > sum 的情況,還是有隱患的。這些問題我們接下來繼續解決。


問題3main_counter 爲毛比 sum 大了?

原因:還是競爭。調整加鎖的位置。

   其實這是主線程輸出的問題,問題主要出在以下這段代碼: 
這裏寫圖片描述

第57~61 行是在計算counter[i] 的和,將計算結果保存到sum 中,然後第62行輸出結果。問題是在這個過程中也會發生競爭: 
(1)如果在主線程剛執行完求和操作還未輸出時,時間片用完了,CPU被子線程搶佔,執行了main_counter++,但sum 不會再同步增加了,所以最後輸出時,main_counter > sum 。 
(2)如果是多核CPU,在主線程完成求和操作到輸出結果這一段時間內很可能有子線程在並行執行main_counter++,同樣sum 卻不會增加,導致輸出時,main_counter > sum 。


那在單核系統上爲什麼代碼2 執行幾乎是正常的呢? 
   在單核系統上,運行出現異常是原因(1)導致,因爲單核上CPU調度線程是用的時間片輪轉。大概因爲57~62 行這幾條語句執行時間太短了,一個時間片內可以執行完,幾乎不會在中途被打斷。


   我們可以在62行前加 sleep 睡眠,這時,隱患就暴露出來了。 
這裏寫圖片描述

然後在我的單核雲服務器上運行: 
這裏寫圖片描述

果然,main_counter 比 sum 大了。


解決辦法:調整鎖的位置

   解決問題的關鍵就是 a、要讓 main_counter++ 和 counter[i]++ 是保持同步更新的, 這兩條語句中間不能被打斷; b、求和操作完成後,不能再讓 main_counter 增加。


我們把解鎖操作移到 62 行之後就可以了。

最終的完整代碼如下:

<code class="hljs cpp has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include<stdio.h></span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include<stdlib.h></span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include<sys/types.h></span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include<unistd.h></span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include<ctype.h></span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include<pthread.h></span>

<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#define MAX_THREAD  3  <span class="hljs-comment" style="box-sizing: border-box;">//線程個數</span></span>

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//初始化鎖</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> pthread_mutex_t    mutex = PTHREAD_MUTEX_INITIALIZER;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span>   main_counter,counter[MAX_THREAD]={<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>};

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>* thread_worker(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>*  arg)
{
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//先將void* 轉爲 int* 再賦值</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>  thread_num = *(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>*)arg;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//釋放內存</span>
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">free</span>((<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>*)arg);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(;;)
    {
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//加鎖</span>
        pthread_mutex_lock(&mutex);
        counter[thread_num]++;    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//本線程的counter 加 1</span>
        main_counter++;
    }
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> main(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> argc,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">char</span>* argv[])
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>                 i,rtn,ch;
    pthread_t           pthread_id[MAX_THREAD] =  {<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>};  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//存放線程</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>                 *param;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(i=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;i<MAX_THREAD;i++)
    { 
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//申請內存臨時保存參數</span>
        param = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>*)<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">malloc</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">sizeof</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>));
        *param = i;
        pthread_create(&pthread_id[i],NULL,thread_worker,param);
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">do</span>
    {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span>   sum = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(i=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;i<MAX_THREAD;i++)
        {
            sum += counter[i];
            <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"No.%d: %llu\n"</span>,i,counter[i]);
        }
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">printf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%llu/%llu\n"</span>,main_counter,sum);
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//解鎖</span>
        pthread_mutex_unlock(&mutex);
    }<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span>((ch = getchar())!=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'q'</span>);

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//銷燬鎖資源</span>
    pthread_mutex_destroy(&mutex);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li></ul>

運行: main_counter == sum ,與理論符合 
這裏寫圖片描述

  解決了所有問題後,線程運行的效率遠遠的變慢了,這是因爲鎖的存在導致一個線程在運行時,其他線程幾乎是在阻塞的。但是大可不必在意這個,因爲這個程序只是用來幫助更好的理解線程資源共享、線程並行、線程搶佔和線程調度的,實際應用中,肯定不會把一個求和操作搞的這麼錯綜複雜的。




謝謝大家,本文轉載於http://blog.csdn.net/lyh__521/article/details/49759111      點擊打開鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章