以下以win32平臺(tái)為例。我們先看一個(gè)非多線程的程序:
#include <iostream>
#include <windows.h>
DWORD WINAPI thread_func(LPVOID pN)
{
for (int i = 0; i < *((int*)pN); ++i) {
std::cout << i+1 << "\t";
}
std::cout << std::endl;
throw "ok.";
std::cout << "thread_func() done." << std::endl;
return 0;
}
int main(int argc, char* argv[])
{
int n = 5;
try{
thread_func((LPVOID)&n);
Sleep(2000);
}
catch (const char* s) {
std::cerr << s << std::endl;
exit(1);
}
std::cout << "main() done." << std::endl;
return 0;
}
可以看到,函數(shù)thread_func()可以正確的拋出異常并被main()的catch捕捉。但是,如果用一個(gè)新線程來(lái)運(yùn)行thread_func()會(huì)出現(xiàn)什么情況呢?
#include <iostream>
#include <windows.h>
DWORD WINAPI thread_func(LPVOID pN)
{
for (int i = 0; i < *((int*)pN); ++i) {
std::cout << i+1 << "\t";
}
std::cout << std::endl;
throw "ok.";
std::cout << "thread_func() done." << std::endl;
return 0;
}
int main(int argc, char* argv[])
{
HANDLE hThrd;
DWORD thrdId;
int n = 5;
try{
hThrd = CreateThread( NULL,
0,
thread_func,
(LPVOID)&n,
0,
&thrdId);
Sleep(2000);
}
catch (const char* s) {
std::cerr << s << std::endl;
exit(1);
}
std::cout << "main() done." << std::endl;
return 0;
}
很不幸,這個(gè)程序編譯的時(shí)候是可以通過(guò)的,但是運(yùn)行時(shí)出錯(cuò):
1 2 3 4 5
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
請(qǐng)按任意鍵繼續(xù). . .
而且同時(shí)會(huì)有一個(gè)運(yùn)行時(shí)錯(cuò)誤的提示。事實(shí)上,這個(gè)錯(cuò)誤提示意味著程序在沒(méi)有發(fā)現(xiàn)try{}的時(shí)候看到了throw。
通過(guò)試驗(yàn),我發(fā)現(xiàn)系統(tǒng)(這里是win32)不能將CreateThread()所產(chǎn)生的線程歸結(jié)到try{}中。更加嚴(yán)重的情況是,即使用一個(gè)函數(shù)囊括了整個(gè)程序,然后try這個(gè)函數(shù),其他線程依然脫離了這個(gè)try。
所以,一個(gè)解決方法是,凡是遇到新的線程,必須在新線程中重新寫異常處理。不然,就如google代碼標(biāo)準(zhǔn)里所說(shuō)的那樣,不使用C++的異常機(jī)制。畢竟C++沒(méi)有定義多線程的標(biāo)準(zhǔn),所以也就無(wú)從說(shuō)起多線程中異常處理的標(biāo)準(zhǔn)。
最后附上在新線程寫異常處理的參考:
#include <iostream>
#include <windows.h>
DWORD WINAPI thread_func(LPVOID pN)
{
try{
for (int i = 0; i < *((int*)pN); ++i) {
std::cout << i+1 << "\t";
}
std::cout << std::endl;
throw "ok.";
}
catch (const char* s) {
std::cerr << s << std::endl;
exit(1);
}
std::cout << "thread_func() done." << std::endl;
return 0;
}
int main(int argc, char* argv[])
{
HANDLE hThrd;
DWORD thrdId;
int n = 5;
hThrd = CreateThread( NULL,
0,
thread_func,
(LPVOID)&n,
0,
&thrdId);
Sleep(2000);
std::cout << "main() done." << std::endl;
return 0;
}