一、(LINUX 執行緒同步) 引入
原創水平有限有誤請指出
執行緒相比程式有著先天的資料共享的優勢,如下圖,執行緒共享了程式除棧區以外的所有記憶體區域如下圖所示:
但是這種共享有時候也會帶來問題,簡單的考慮如下C++程式碼:
實際上很簡單我就是建立了一個全域性變數,這個全域性變數是全部執行緒共享,我開啟了3個執行緒同時對裡面的共享
資料進行更改,當
#define MAXOUT 100
的時候這個時候最後輸出如下:
last numer: 300
顯然沒有問題,但是如果我將
#define MAXOUT 1000000
增大到100W的時候最後輸出為:
last numer: 2999972
我們明顯的感覺到資料不對了,少了一些
出現這種問題在於,多個執行緒對同一個共享資源進行訪問,因為執行緒是CPU排程的單位,而
假設這個時候a 為 1000:
這段程式碼並不是原子性的,假設執行緒1正在修改
b = a;
這個時候時間片用完,執行緒2也執行這段程式碼,因為
a = b+1;並沒有執行,所以共享區域的資料還沒有變化
執行緒2拿到的資料任然是1000,也執行如下程式碼
b = a;
a = b+1;
這個時候執行緒2完成了修改,a為1001
當下一次執行緒1拿到CPU時間片,再次從就緒狀轉到執行態,接著
執行
a = b+1;
因為執行緒1中的b還是1000,所以a再次修改為1001,實際這個時候
是1002才對,執行緒2的修改被覆蓋,出現上面的問題,透過語言的描述
也許不太明白,下面的時序圖會幫助理解:
遇到這種問題當然就引入了我們的執行緒間同步的方法,常用的
1、互斥鎖、條件變數
2、讀寫鎖
3、訊號量
4、spinlock
他們保護的是一段臨界區程式碼,所謂臨界區就是可能出現對同一個共享資源進行修改的程式碼,比如我這裡
就是臨界區程式碼
後面將對他們進行描述,這裡我們簡單實用靜態互斥鎖進行解決這個問題。
實際上我們就是保護了運算子過載的testc& operator++()
臨界區的選擇應該儘量小,避免對多執行緒的併發性產生較大的效能影響
具體程式碼如下:
注意:一個簡單型別的i++也不一定是一個原子操作,所以在涉及到併發修改共享變數的時候一定要使用
執行緒同步手段。
作者微信:
執行緒相比程式有著先天的資料共享的優勢,如下圖,執行緒共享了程式除棧區以外的所有記憶體區域如下圖所示:
但是這種共享有時候也會帶來問題,簡單的考慮如下C++程式碼:
點選(此處)摺疊或開啟
-
/*************************************************************************
-
> File Name: error.cpp
-
> Author: gaopeng QQ:22389860 all right reserved
-
> Mail: gaopp_200217@163.com
-
> Created Time: Mon 15 May 2017 12:01:33 AM CST
-
************************************************************************/
-
-
#include<iostream>
-
#include <pthread.h>
-
#include <string.h>
-
#define MAXOUT 1000000
-
using namespace std;
-
-
-
-
class testc
-
{
-
private:
-
int a;
-
public:
-
testc()
-
{
-
a = 1;
-
}
-
testc& operator++()
-
{
-
int b = 0;
-
b = a;
-
a = b+1;
-
return *this;
-
}
-
void prit()
-
{
-
cout<<a<<endl;
-
}
-
};
-
-
-
testc test = test;
-
-
-
void* testp(void* arg)
-
{
-
int i = MAXOUT;
-
while(i--)
-
{
-
++test;
-
cout<<pthread_self() <<":";
-
test.prit();
-
}
-
}
-
-
-
-
-
int main(void)
-
{
-
pthread_t tid[3];
-
int er;
-
int i = 0;
-
-
while(i<3)
-
{
-
-
if ((er = pthread_create(tid+i,NULL,testp,NULL) )!=0 )
-
{
-
strerror(er);
-
return -1;
-
}
-
i++;
-
}
-
-
i = 0;
-
-
while(i<3)
-
{
-
pthread_join(*(tid+i),NULL);
-
i++;
-
}
-
cout<<"last numer: ";
-
test.prit();
- }
實際上很簡單我就是建立了一個全域性變數,這個全域性變數是全部執行緒共享,我開啟了3個執行緒同時對裡面的共享
資料進行更改,當
#define MAXOUT 100
的時候這個時候最後輸出如下:
last numer: 300
顯然沒有問題,但是如果我將
#define MAXOUT 1000000
增大到100W的時候最後輸出為:
last numer: 2999972
我們明顯的感覺到資料不對了,少了一些
出現這種問題在於,多個執行緒對同一個共享資源進行訪問,因為執行緒是CPU排程的單位,而
點選(此處)摺疊或開啟
-
{
-
int b = 0;
-
b = a;
-
a = b+1;
-
return *this;
- }
假設這個時候a 為 1000:
這段程式碼並不是原子性的,假設執行緒1正在修改
b = a;
這個時候時間片用完,執行緒2也執行這段程式碼,因為
a = b+1;並沒有執行,所以共享區域的資料還沒有變化
執行緒2拿到的資料任然是1000,也執行如下程式碼
b = a;
a = b+1;
這個時候執行緒2完成了修改,a為1001
當下一次執行緒1拿到CPU時間片,再次從就緒狀轉到執行態,接著
執行
a = b+1;
因為執行緒1中的b還是1000,所以a再次修改為1001,實際這個時候
是1002才對,執行緒2的修改被覆蓋,出現上面的問題,透過語言的描述
也許不太明白,下面的時序圖會幫助理解:
遇到這種問題當然就引入了我們的執行緒間同步的方法,常用的
1、互斥鎖、條件變數
2、讀寫鎖
3、訊號量
4、spinlock
他們保護的是一段臨界區程式碼,所謂臨界區就是可能出現對同一個共享資源進行修改的程式碼,比如我這裡
點選(此處)摺疊或開啟
-
{
-
int b = 0;
-
b = a;
-
a = b+1;
-
return *this;
- }
就是臨界區程式碼
後面將對他們進行描述,這裡我們簡單實用靜態互斥鎖進行解決這個問題。
點選(此處)摺疊或開啟
-
//原子操作 加鎖
-
pthread_mutex_lock(&mtx);
-
++test;
-
pthread_mutex_unlock(&mtx);
-
//原子操作 解鎖
-
cout<<pthread_self() <<":";
- test.prit()
臨界區的選擇應該儘量小,避免對多執行緒的併發性產生較大的效能影響
具體程式碼如下:
點選(此處)摺疊或開啟
-
/*************************************************************************
-
> File Name: error.cpp
-
> Author: gaopeng QQ:22389860 all right reserved
-
> Mail: gaopp_200217@163.com
-
> Created Time: Mon 15 May 2017 12:01:33 AM CST
-
************************************************************************/
-
-
#include<iostream>
-
#include <pthread.h>
-
#include <string.h>
-
#define MAXOUT 1000000
-
using namespace std;
-
-
static pthread_mutex_t mtx=PTHREAD_MUTEX_INITIALIZER;
-
-
-
class testc
-
{
-
private:
-
int a;
-
public:
-
testc()
-
{
-
a = 1;
-
}
-
testc& operator++()
-
{
-
int b = 0;
-
b = a;
-
a = b+1;
-
return *this;
-
-
}
-
void prit()
-
{
-
cout<<a<<endl;
-
}
-
};
-
-
-
testc test = test;
-
-
-
void* testp(void* arg)
-
{
-
int i = MAXOUT;
-
-
while(i--)
-
{
-
//原子操作 加鎖
-
pthread_mutex_lock(&mtx);
-
++test;
-
pthread_mutex_unlock(&mtx);
-
//原子操作 解鎖
-
cout<<pthread_self() <<":";
-
test.prit();
-
}
-
}
-
-
-
-
-
int main(void)
-
{
-
pthread_t tid[3];
-
int er;
-
int i = 0;
-
-
while(i<3)
-
{
-
-
if ((er = pthread_create(tid+i,NULL,testp,NULL) )!=0 )
-
{
-
strerror(er);
-
return -1;
-
}
-
i++;
-
}
-
-
i = 0;
-
-
while(i<3)
-
{
-
pthread_join(*(tid+i),NULL);
-
i++;
-
}
-
cout<<"last numer: ";
-
test.prit();
- }
注意:一個簡單型別的i++也不一定是一個原子操作,所以在涉及到併發修改共享變數的時候一定要使用
執行緒同步手段。
作者微信:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/7728585/viewspace-2137980/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 4、Linux多執行緒,執行緒同步(2)Linux執行緒
- Linux核心同步,程式,執行緒同步薦Linux執行緒
- c#執行緒-執行緒同步C#執行緒
- 執行緒同步及執行緒鎖執行緒
- 執行緒同步執行緒
- 多執行緒和多執行緒同步執行緒
- 執行緒同步的情景之一執行緒
- java執行緒學習5——執行緒同步之同步方法Java執行緒
- 執行緒與同步非同步執行緒非同步
- 執行緒的同步執行緒
- 理解執行緒同步執行緒
- 深入執行緒同步執行緒
- Java—執行緒同步Java執行緒
- 多執行緒同步執行緒
- .net執行緒同步執行緒
- 執行緒同步方法執行緒
- Java執行緒:執行緒的同步與鎖Java執行緒
- 【多執行緒總結(二)-執行緒安全與執行緒同步】執行緒
- 多執行緒(2)-執行緒同步互斥鎖Mutex執行緒Mutex
- 非同步/同步,阻塞/非阻塞,單執行緒/多執行緒概念梳理非同步執行緒
- java 多執行緒 –同步Java執行緒
- 執行緒同步機制執行緒
- java 多執行緒 --同步Java執行緒
- NPTL 執行緒同步方式執行緒
- Java多執行緒學習(3)執行緒同步與執行緒通訊Java執行緒
- 多執行緒下的程式同步(執行緒同步問題總結篇)執行緒
- 別再被多執行緒搞暈了!一篇文章輕鬆搞懂 Linux 多執行緒同步!執行緒Linux
- C#多執行緒開發-執行緒同步 02C#執行緒
- #大學#Java多執行緒學習02(執行緒同步)Java執行緒
- 多執行緒(2)-執行緒同步條件變數執行緒變數
- Java之美[從菜鳥到高手演變]之執行緒同步的引入Java執行緒
- Java多執行緒—執行緒同步(單訊號量互斥)Java執行緒
- JAVA多執行緒詳解(3)執行緒同步和鎖Java執行緒
- Java多執行緒之執行緒同步【synchronized、Lock、volatitle】Java執行緒synchronized
- iOS多執行緒程式設計:執行緒同步總結iOS執行緒程式設計
- .NET多執行緒程式設計(3):執行緒同步 (轉)執行緒程式設計
- POSIX執行緒程式設計起步(2)-執行緒同步 (轉)執行緒程式設計
- Posix執行緒程式設計指南(3)-執行緒同步 (轉)執行緒程式設計