# C++ 线ç¨
## çº¿ç¨æé
è°ç¨thread classçæé 彿°ï¼å¯ä»¥ä¼ å
¥ä¸ä¸ªå½æ°ï¼åé¢è·ç彿°çåæ°ãæé ä¹åä¼é©¬ä¸å¼å¯ä¸ä¸ªçº¿ç¨å¹¶æ§è¡ã
```cpp
#include
#include
using namespace std;
void do_something(int v) {
std::this_thread::sleep_for(chrono::milliseconds(2000));
cout << v << endl;
}
int main() {
thread th(do_something, 3);
while(true){}
}
```
è¿æä¸ä¸ªç§æé æ¹æ³ï¼ä¼ å
¥ä¸ä¸ªéè½½äº()è¿ç®ç¬¦ç对象ï¼thread对象å
é¨ä¼èªå¨æ§è¡ã
```cpp
class DoSomething {
public:
DoSomething(int v): _v(v) {};
void operator()() { // éè½½()
std::this_thread::sleep_for(chrono::milliseconds(2000));
cout << _v << endl;
}
private:
int _v;
};
int main() {
thread th(DoSomething(3));
while(true){}
}
```
ä¼ å
¥lambda彿°ä¹æ¯å¯è¡çã
```cpp
thread th2([](int v) {
std::this_thread::sleep_for(chrono::milliseconds(2000));
cout << v << endl;
}, 3);
```
## 线ç¨ID
å¯ä»¥éè¿ std::this_thread::get_id() æ¥è·åå½å线ç¨çIDã
```cpp
void do_something(int v) {
std::this_thread::sleep_for(chrono::milliseconds(2000));
cout << "do_something: " << std::this_thread::get_id() << endl;
}
int main() {
thread th(do_something, 3);
cout << "main: " << std::this_thread::get_id() << endl;
while(true){}
}
```
è¾åºï¼
```cpp
main: 1
do_something: 2
```
å¯ä»¥åç°çº¿ç¨IDæ¯ä»1å¼å§éå¢çã
使³¨æget_id()çè¿åç±»å䏿¯ä¸ä¸ªæ´æ°ï¼èä¸ä¸ªthread::idç±»åï¼æä»¬è½çå°æ´æ°æ¯å 为å®éè½½äºè¾åºè¿ç®ç¬¦ãçä¸ä¸å®çæé æ¹æ³ï¼
```cpp
class id {
native_handle_type _M_thread;
public:
id() noexcept : _M_thread() { }
explicit id(native_handle_type __id) : _M_thread(__id) { }
// ...
```
å
é¨åæé äºnative_handle_typeè¿ä¸ªç±»åãä¸ç´å¯»æ¾è¿ä¸ªç±»åçæç»å½¢æï¼å¯ä»¥åç°å
¶å®å°±æ¯ä¸ä¸ªuintptr_tç±»åã
```cpp
typedef uintptr_t pthread_t;
typedef unsigned __int64 uintptr_t;
```
thread对象çå
鍿å_M_idçç±»åå°±æ¯thread::idï¼å½å¼å¯ä¸ä¸ªçº¿ç¨æ¶ï¼_M_idä¼è¢«èµäºä¸ä¸ªçº¿ç¨IDã
## 线ç¨ç»æä¸éæ¯
çº¿ç¨ææ§è¡ç代ç åç»æå线ç¨å°±ä¼èªå¨éæ¯ï¼è¿ä¸ªè¿ç¨ç±æä½ç³»ç»å®æï¼èç¨æ·æç¨åºçthread对象æå_M_idä¼è¢«é置为thread::id()ï¼å³thread::id()çé»è®¤æé 彿°ï¼å³_M_thread=0ã
妿å¨OSçº¿ç¨æªç»æçæ
åµä¸ï¼éæ¯äºthread对象ä¼åçä»ä¹ï¼å¯ä»¥çä¸ä¸threadçææå½æ°ï¼
```cpp
~thread() {
if (joinable())
std::terminate();
}
bool joinable() const noexcept {
return _M_id != id()
}
```
妿joinable()=trueï¼å°±ä¼è°ç¨std::terminate()ç»æ¢å½åè¿ç¨ï¼æ³¨æä¸æ¯ç»æ¢çº¿ç¨èæ¯ç»æ¢æ´ä¸ªè¿ç¨ãjoinable()å
¶å®å°±æ¯æ¯è¾äºä¸ä¸çº¿ç¨IDï¼çç对象éç_M_idæ¯ä¸æ¯è¢«éç½®è¿ã妿_M_id != id()ï¼å_M_idè¿æ²¡è¢«éç½®ï¼æå³ç线ç¨è¿æ²¡ç»æãå¦æä½ è¦éæ¯è¿ä¸ªå¯¹è±¡æ¯ä¸åæ³è¡ä¸ºï¼åä¼å¼ºå¶éåºè¿ç¨ï¼æ§å¶å°ä¼æå° terminate called without an active exception ã
```cpp
void do_something(int v) {
std::this_thread::sleep_for(chrono::milliseconds(2000));
}
int main() {
thread* th = new thread(do_something, 3);
delete th;
}
```
## join
joinçæææ¯è¿æ¥ï¼è°ç¨`thread->join()`æå³çä¸ä¸ªçº¿ç¨åå¦ä¸ä¸ªçº¿ç¨è¿æ¥å¨ä¸èµ·ï¼åªæçº¿ç¨1æ§è¡å®åï¼çº¿ç¨2æç»§ç»æ§è¡ã
```cpp
void do_something(int v) {
std::this_thread::sleep_for(chrono::milliseconds(2000));
cout << "thread 1 end" << endl;
}
int main() {
thread* th = new thread(do_something, 3);
thread th2([&]() {
th->join();
cout << "thread 2 end" << endl;
});
while (true) {}
}
```
è¾åºï¼
```
thread 1 end
thread 2 end
```
æä»¬åå头æ³ä¸ä¸ï¼ä¸ºä»ä¹ææå½æ°éç夿彿°å«joinable()ï¼ä¸ªäººæè§æ¯å 为ä¸ä¸ªç»æçè¿ç¨ä¸å¯è½åjoinï¼èæªç»æè¿ç¨æè½joinãä½è¿ä¸ªå¹¶ä¸å½±åjoin()彿°çè°ç¨ï¼å 为æå®éªåç°join()彿°å°±ç®è°ç¨å¤æ¬¡ä¹ä¸ä¼æ¥éã
## detach
detachæå³çè±ç¦»ï¼è°ç¨detach()åï¼OS线ç¨ä¸ååthread对象æ§å¶ï¼_M_idä¼è¢«éç½®ï¼å³ä½¿ä½ æthreadå¯¹è±¡éæ¯ï¼çº¿ç¨ä»ç¶è¿è¡ãä½ä»OSå±é¢ä¸ï¼ä¸»çº¿ç¨éåºåå线ç¨ä¾æ§ä¼è¢«å¼ºå¶éåºã
```cpp
void do_something(int v) {
std::this_thread::sleep_for(chrono::milliseconds(2000));
cout << "thread 1 end" << endl;
}
int main() {
thread* th = new thread(do_something, 3);
th->detach();
delete th; // delete thread object
while (true) {}
}
// thread 1 end
```
## å¼å¸¸å¤ç
C++çå¼å¸¸å¤çæ¯ä¸ªéå¸¸æ£æçé®é¢ï¼ä¸æ¦åçå¼å¸¸ï¼å½æ°ä¼è¢«ç»æ¢å¹¶æåºå¼å¸¸ï¼å¯¼è´åæ¬è¯¥æ§è¡çä»£ç æ æ³è¢«æ§è¡ï¼æ¯å¦åæ¶å
åã对äºçº¿ç¨åºæ¯ä¸ï¼ä¸æ¦åçå¼å¸¸ï¼å½æ°ç»æ¢ï¼å¯¼è´threadèªå¨å¯¹è±¡çææå½æ°è°ç¨ï¼è¿è导è´è¿ç¨ç»æ¢ã
å
çä¸ä¸ªé误示ä¾ï¼
```cpp
int main() {
try {
thread th = thread(do_something, 3);
throw runtime_error("test");
} catch (runtime_error& e) {
}
while (true) {}
}
```
throwä¸ä¸ªé误åï¼å°±é©¬ä¸ç¦»å¼äºtry代ç åï¼èªå¨åéthè°ç¨ææå½æ°ï¼ä½å¯è½çº¿ç¨è¿æ²¡ç»æï¼è¿ä¼å¯¼è´è¿ç¨ä¼è¢«ç»æ¢ã
è§£å³åæ³æ¯éè¿âèµæºè·åå³åå§åâ(RAIIï¼Resource Acquisition Is Initialization)è¿è¡è§é¿ï¼
```cpp
class ThreadGuard {
thread& t_;
public:
explicit ThreadGuard(thread& t): t_(t) {}
~ThreadGuard() {
if(t_.joinable()) {
t_.join();
}
}
};
int main() {
try {
thread th = thread(do_something, 3);
ThreadGuard tg(th);
throw runtime_error("test");
} catch (runtime_error& e) {
}
while (true) {}
}
```
æä»¬å¨èªå¨åétgçææå½æ°éé¢è°ç¨threadçjoinæ¹æ³ï¼ä½¿å
¶å¨è¢«è°ç¨æ¶è½å¤çå¾
çº¿ç¨æ§è¡å®æ¯ã
## åæ°ä¼ é
### å¼ç¨ä¼ é
C++å¯ä»¥ä¼ å¼ç¨ç±»åï¼ä½threadçæé 彿°å¹¶ä¸è½å辨æ¯å¦åºè¯¥ä¼ éå¼ç¨ï¼è¿æ¶ä½ å¯ä»¥éè¿æé reference_wrapperæ¥æ¾ç¤ºå£°æéè¦ä¼ éå¼ç¨ï¼
```cpp
void handle(string& s) {
cout << s << endl;
}
int main() {
string s = "hello";
thread th(handle, std::ref(s));
while (true) {}
}
```
### ç±»æ¹æ³ä¼ é
å¯ä»¥éè¿ä¼ å
¥ ç±»æ¹æ³å°å+对象å°å çå½¢å¼ææ¹æ³ä¼ å
¥thread对象ã
```cpp
struct Handle {
void do_something(int v) {
cout << v << endl;
}
};
int main() {
Handle h;
thread th(&Handle::do_something, &h, 99999);
while (true) {}
}
// 99999
```
### åæ°æææè½¬ç§»
éè¿move()æé
unique_ptrå¯ä»¥å®ææææè½¬ç§»ï¼åä¸å»æ»æ¯åªæä¸ä¸ªçº¿ç¨æ¥ææ°æ®çæææï¼è¿æ¯ä¸ä¸ªè§£å³æ°æ®ç«äºçè¯å¥½è§£å³åæ³ã
```cpp
void handle(unique_ptr s) {
cout << *s << endl;
}
int main() {
unique_ptr data(new string("hello"));
thread th(handle, move(data));
while (true) {}
}
// hello
```