C/C++函式的本質以及多執行緒函式的呼叫過程
C/C++中,函式的本質是一段可執行程式碼,程式碼包括了局部變數、全域性變數的地址等等。到組合語言的級別,變數函式等都可以視為彙編的程式碼片段。函式的本質就是一個可執行程式碼片段的集合
執行緒的詳細介紹:http://www.cnblogs.com/tracylee/archive/2012/10/29/2744228.html
一個執行緒有自己的空間,有自己的區域性變數。當一個執行緒執行一個函式的時候,會複製函式的程式碼段到自己的執行緒空間,之後執行該程式碼段。對於區域性變數,每個執行緒會儲存一個區域性變數的副本,因為區域性變數是儲存在棧記憶體,所以一個執行緒更改區域性變數不會影響其他執行緒的區域性變數。全域性變數是儲存在堆記憶體上的,因此可以理解為執行緒是直接操作堆記憶體上的全域性變數,因此如果一個執行緒改了全域性變數,那麼其他執行緒對應的全域性變數肯定會更改,因為堆記憶體只有一個。
在多執行緒程式設計的過程中,所謂的新增互斥量、鎖和條件變數等,本質上是為了保護堆記憶體上的東西,或者說是全域性變數。所謂的競爭條件也是指的全域性的,函式內部的區域性的東西,不會引起競爭!!!!!
可以這麼認為,對於C++11中的std:thread
來說,函式是其執行的基本單位,這裡說的函式包括普通函式、函式物件、std::funtion
、仿函式、lambda
表示式等。執行的時候,執行緒會複製函式的程式碼片段到自己的執行緒空間中去執行。執行緒空間的本身是封閉的,也就是說一個同級別的執行緒不能更改另一個執行緒的程式碼片段。。我們說的執行緒之間的通訊,本質上說的是通過全域性變數的狀態,使得不同執行緒之間可以相互通訊!!!
對於類的成員函式來說,執行緒複製函式的時候,類的成員變數相對於執行緒來說也是全域性!!!!
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
static int N = 0;
void fun(int n) {
int t = 0;
for (int i = 0; i < n; ++i) {
++t;
++N;
}
std::this_thread:: sleep_for(std::chrono::milliseconds(100));
std::cout << "local: " << t << std::endl;
std::cout << "global: " << N << std::endl;
}
class C {
public:
void fun(int n) {
int t = 0;
for (int i = 0; i < n; ++i) {
++t;
++_N;
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "local: " << t << std::endl;
std::cout << "global: " << _N << std::endl;
}
int _N; // 這裡的_N相對於fun函式是全域性的!!!!!!!
};
int main() {
// 函式的例子
std::cout << "function example:\n";
std::thread t1(fun, 100000);
std::thread t2(fun, 100000);
t1.join();
t2.join();
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// 類的例子
std::cout << "\nclass example:\n";
C c;
c._N = 0;
std::thread t3(&C::fun, &c, 100000);
std::thread t4(&C::fun, &c, 100000);
t3.join();
t4.join();
return 0;
}
一種可能的執行結果:
function example:
local: 100000
global: 109248
local: 100000
global: 109248
class example:
local: 100000
global: 115581
local: 100000
global: 115581