多線程場景中的棧內存異常
在子線程中嘗試使用當前函數的資源,是非常危險的,但是C++支持這么做。因此C++這么做可能會造成棧內存異常。
正常代碼
#include <iostream>
#include <thread>
#include <windows.h>// 線程函數,用于執行具體的任務
void fun(int param)
{std::cout << __FUNCTION__ << " param:" << param << std::endl;Sleep(3000);param = 1;std::cout << __FUNCTION__ << " param:" << param << std::endl;
}// 線程函數,用于執行具體的任務
void threadFunction() {// 在這里執行線程的具體任務int num = 2;//在函數中還啟動了一個線程std::thread funThread([num](){fun(num);});funThread.detach();
}int main() {const int numThreads = 3;std::thread threads[numThreads];// 創建并啟動多個線程for (int i = 0; i < numThreads; ++i) {threads[i] = std::thread(threadFunction);}//等待所有線程執行完畢for (int i = 0; i < numThreads; ++i) {threads[i].join();}Sleep(1000);std::cout << "All threads have completed." << std::endl;return 0;
}
上述是一個正常的多線程代碼。
異常代碼
但是如果將其中多線程傳參設置為引用傳遞,可能就會造成內存泄露了,如下所示:
#include <iostream>
#include <thread>
#include <windows.h>// 線程函數,用于執行具體的任務
void fun(int& param)//傳參修改為引用傳遞
{std::cout << __FUNCTION__ << " param:" << param << std::endl;Sleep(3000);param = 1;std::cout << __FUNCTION__ << " param:" << param << std::endl;
}// 線程函數,用于執行具體的任務
void threadFunction() {// 在這里執行線程的具體任務int num = 2;//在函數中還啟動了一個線程,傳參為引用std::thread funThread([&num](){fun(num);});funThread.detach();
}int main() {const int numThreads = 3;std::thread threads[numThreads];// 創建并啟動多個線程for (int i = 0; i < numThreads; ++i) {threads[i] = std::thread(threadFunction);}//等待所有線程執行完畢for (int i = 0; i < numThreads; ++i) {threads[i].join();}Sleep(1000);std::cout << "All threads have completed." << std::endl;return 0;
}
編譯成功,但是運行失敗。
運行結果:
上面std::thread funThread(&num{fun(num);});,采用引用傳遞,并且void fun(int& param)中也采用引用入參的形式。此時可能就會產生內存泄露。
因為傳入參數num是一個局部參數,我們在fun中修改或讀取param時,可能num已經被釋放掉了,這時候修改或者讀取param就會發生內存錯誤,其實這里是棧內存異常。這是非常危險的,因為棧內存可能會造成無法估量的問題。
優化代碼
當然我們用引用傳遞的好處是可以避免臨時變量的產生,但變量是復雜對象時,還是可以很大程度減少內存消耗。雖然不能用引用,但是我們可以使用std::move來實現變量所有權的轉移,也可以減少臨時變量的拷貝。
#include <iostream>
#include <thread>
#include <windows.h>// 線程函數,用于執行具體的任務
void fun(int&& param)//右值傳參
{std::cout << __FUNCTION__ << " param:" << param << std::endl;Sleep(3000);param = 1;std::cout << __FUNCTION__ << " param:" << param << std::endl;
}// 線程函數,用于執行具體的任務
void threadFunction() {// 在這里執行線程的具體任務int num = 2;//在函數中還啟動了一個線程std::thread funThread(fun, std::move(num));//使用move傳入右值funThread.detach();
}int main() {const int numThreads = 3;std::thread threads[numThreads];// 創建并啟動多個線程for (int i = 0; i < numThreads; ++i) {threads[i] = std::thread(threadFunction);}//等待所有線程執行完畢for (int i = 0; i < numThreads; ++i) {threads[i].join();}Sleep(1000);std::cout << "All threads have completed." << std::endl;return 0;
}