สืบเนื่องจากการใช้งาน std::thread ซึ่งผมคิดไปเองว่า gcc น่าจะรองรับมาตรฐาน C++11 ไปเรียบร้อยแล้ว แต่ปรากฎว่าไม่เป็นเช่นนั้นเนื่องจาก gcc ที่ใช้อยู่ในปัจจุบันเป็นรุ่นที่ 4.6 ยังไม่รองรับทั้งหมด (สถานะของมาตรฐาน c++ สำหรับ gcc 4.6 สามารถดูได้จาก Status of Experimental C++0x Support in GCC 4.6) และ std::thread ถึงแม้จะใช้งานได้บ้างแล้ว (สร้าง std::thread อ็อบเจกต์ได้ join ได้ แต่อินเทอร์รัพท์ไม่ได้) แต่ก็ยังต้องรอให้เธรดที่ถูกสร้างขึ้นจบการทำงานไปตามปรกติวิสัย ซึ่งในงานบางอย่างจำเป็นต้องใช้การอินเทอร์รัพท์เข้าช่วย ซึ่งในบทความนี้จะทดลองใช้งานไลบรารีเธรดจาก boost แทน
เหตุผลนึ่งที่เลือกไลบรารีจาก boost เนื่องจาก boost::thread นั้นเหมือนกับมาตฐาน C++11 มากทีเดียว หาก gcc อิมพลีเมนท์ std::thread พร้อมที่จะให้ใช้งานแล้วการย้ายกลับไปใช้ std::thread จะทำได้ไม่ยากนัก เริ่มจากตัวอย่างง่ายๆ กันก่อน (ลอกตัวอย่างจาก เรื่องวุ่นๆ ของ std::thread ใน C++0x)
คอมไพล์และเรียกทำงาน $ g++ boost_thread.cpp -lboost_thread
$ ./a.out
pass dw1 to thread
this in constructor : 0x7fff9ff7c28f
show running : 0
show this in show : 0x7fff9ff7c28f
show running by operator : 0
show this by operator : 0x25ef1f8
show running : 1
show this in show : 0x7fff9ff7c28f
show running by operator after wake up : 0
pass dw2 to thread
this in constructor : 0x7fff9ff7c26f
show running : 0
show this in show : 0x7fff9ff7c26f
show running by operator : 0
show this by operator : 0x7fff9ff7c26f
show running : 1
show this in show : 0x7fff9ff7c26f
show running by operator after wake up : 1
ตัวอย่างต่อไปนี้ใช้ทดสอบการอินเทอร์รัพท์ โคดด้านล่างเป็นตัวอย่างที่ไม่มี อินเทอร์รัพท์
คอมไพล์และเรียกทำงาน $ g++ test_interupt.cpp -lboost_thread -lboost_date_time
$ ./a.out
Construct Timer
main sleep: 10s
current time:: 2011-Dec-12 12:13:49.554883
current time:: 2011-Dec-12 12:13:51.555281
current time:: 2011-Dec-12 12:13:53.555459
current time:: 2011-Dec-12 12:13:55.555621
current time:: 2011-Dec-12 12:13:57.555803
main sleep: 10s
current time:: 2011-Dec-12 12:13:59.555971
current time:: 2011-Dec-12 12:14:01.556132
current time:: 2011-Dec-12 12:14:03.556296
current time:: 2011-Dec-12 12:14:05.556461
current time:: 2011-Dec-12 12:14:07.556638
set timer running = false
ทดลอง เอาคอมเมนท์ บรรทดที่ 37 และ 38 ออก
37 // cout << "interrupt thread t" << endl;
38 // t.interrupt();
เป็น
37 cout << "interrupt thread t" << endl;
38 t.interrupt();
คอมไพล์และเรียกทำงานใหม่อีกครั้ง $ g++ test_interupt.cpp -lboost_thread -lboost_date_time
$ ./a.out
Construct Timer
main sleep: 10s
current time:: 2011-Dec-12 12:21:16.090885
current time:: 2011-Dec-12 12:21:18.106295
current time:: 2011-Dec-12 12:21:20.106476
current time:: 2011-Dec-12 12:21:22.106648
current time:: 2011-Dec-12 12:21:24.106809
interrupt thread t
main sleep: 10s
set timer running = false
จะสังเกตได้ว่าเธรด t จะถูกขัดจังหวะการทำงาน ส่งผลให้ไม่มีการแสดงข้อความวันและเวลาออกมาอีก
ข้อพึ่งระวัง เนื่องจาก boost::this_thread::sleep(sleep_time); มีการอิมพลิเมนท์ interrupt point เอาไว้ดังนั้นเราจึงสามารถหยุดการทำงานของเธรดได้หากเราใช้ sleep ซึ่งเป็นฟังก์ชันใน cstdlib แทนเธรดจะไม่ถูกอินเทอร์รัพท์และจะทำงานปรกติแทน
ทดลองเปลี่ยน boost::this_thread::sleep(sleep_time); ในบรรทัดที่ 23 เป็น sleep(sleep_time.total_seconds()); แทนแล้ว คอมไพล์และเรียกทำงานใหม่อีกครั้ง $ g++ test_interupt.cpp -lboost_thread -lboost_date_time
$ ./a.out
Construct Timer
main sleep: 10s
current time:: 2011-Dec-12 12:33:21.625318
current time:: 2011-Dec-12 12:33:23.625694
current time:: 2011-Dec-12 12:33:25.625857
current time:: 2011-Dec-12 12:33:27.626025
current time:: 2011-Dec-12 12:33:29.626215
interrupt thread t
main sleep: 10s
current time:: 2011-Dec-12 12:33:31.626383
current time:: 2011-Dec-12 12:33:33.626552
current time:: 2011-Dec-12 12:33:35.626737
current time:: 2011-Dec-12 12:33:37.626902
current time:: 2011-Dec-12 12:33:39.627088
set timer running = false
เหตุผลนึ่งที่เลือกไลบรารีจาก boost เนื่องจาก boost::thread นั้นเหมือนกับมาตฐาน C++11 มากทีเดียว หาก gcc อิมพลีเมนท์ std::thread พร้อมที่จะให้ใช้งานแล้วการย้ายกลับไปใช้ std::thread จะทำได้ไม่ยากนัก เริ่มจากตัวอย่างง่ายๆ กันก่อน (ลอกตัวอย่างจาก เรื่องวุ่นๆ ของ std::thread ใน C++0x)
// boost_thread.cpp
#include <iostream>
#include <boost/thread.hpp>
using namespace std;
class DoWork
{
public:
DoWork(){
cout << "this in constructor : " << this << endl;
this->running = false;
}
bool running;
void operator()(){
cout << "show running by operator : " << running << endl;
cout << "show this by operator : " << this << endl;
sleep(2);
cout << "show running by operator after wake up : "<< running << endl;
}
void showRunning(){
cout << "show running : " << running << endl;
cout << "show this in show : " << this << endl;
}
};
int main(){
//pass dw to thread by value
cout << "pass dw1 to thread" << endl;
DoWork dw1;
dw1.showRunning();
boost::thread t1(dw1);
sleep(1);
dw1.running = true;
dw1.showRunning();
sleep(1);
t1.join();
//pass dw to thread by reference
cout << endl << "pass dw2 to thread" << endl;
DoWork dw2;
dw2.showRunning();
boost::thread t2(boost::ref(dw2));
sleep(1);
dw2.running = true;
dw2.showRunning();
t2.join();
return 0;
}
คอมไพล์และเรียกทำงาน $ g++ boost_thread.cpp -lboost_thread
$ ./a.out
pass dw1 to thread
this in constructor : 0x7fff9ff7c28f
show running : 0
show this in show : 0x7fff9ff7c28f
show running by operator : 0
show this by operator : 0x25ef1f8
show running : 1
show this in show : 0x7fff9ff7c28f
show running by operator after wake up : 0
pass dw2 to thread
this in constructor : 0x7fff9ff7c26f
show running : 0
show this in show : 0x7fff9ff7c26f
show running by operator : 0
show this by operator : 0x7fff9ff7c26f
show running : 1
show this in show : 0x7fff9ff7c26f
show running by operator after wake up : 1
ตัวอย่างต่อไปนี้ใช้ทดสอบการอินเทอร์รัพท์ โคดด้านล่างเป็นตัวอย่างที่ไม่มี อินเทอร์รัพท์
//test_interupt.cpp
#include <iostream>
using namespace std;
#include <boost/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
class Timer
{
public:
bool running;
Timer(){
cout << "Construct Timer " << endl;
this->running = false;
}
void operator()(){
this->running = true;
while(this->running){
boost::posix_time::ptime current_time = boost::posix_time::microsec_clock::local_time();
cout<<"current time:: "<<current_time<<endl;
boost::posix_time::time_duration sleep_time = boost::posix_time::seconds(2);
boost::this_thread::sleep(sleep_time);
}
}
};
int main(){
Timer timer;
boost::thread t(boost::ref(timer));
cout << "main sleep: 10s"<<endl;
sleep(10);
// cout << "interrupt thread t"<<endl;
// t.interrupt();
cout << "main sleep: 10s"<<endl;
sleep(10);
cout << "set timer running = false"<<endl;
timer.running = false;
t.join();
return 0;
}
คอมไพล์และเรียกทำงาน $ g++ test_interupt.cpp -lboost_thread -lboost_date_time
$ ./a.out
Construct Timer
main sleep: 10s
current time:: 2011-Dec-12 12:13:49.554883
current time:: 2011-Dec-12 12:13:51.555281
current time:: 2011-Dec-12 12:13:53.555459
current time:: 2011-Dec-12 12:13:55.555621
current time:: 2011-Dec-12 12:13:57.555803
main sleep: 10s
current time:: 2011-Dec-12 12:13:59.555971
current time:: 2011-Dec-12 12:14:01.556132
current time:: 2011-Dec-12 12:14:03.556296
current time:: 2011-Dec-12 12:14:05.556461
current time:: 2011-Dec-12 12:14:07.556638
set timer running = false
ทดลอง เอาคอมเมนท์ บรรทดที่ 37 และ 38 ออก
37 // cout << "interrupt thread t" << endl;
38 // t.interrupt();
เป็น
37 cout << "interrupt thread t" << endl;
38 t.interrupt();
คอมไพล์และเรียกทำงานใหม่อีกครั้ง $ g++ test_interupt.cpp -lboost_thread -lboost_date_time
$ ./a.out
Construct Timer
main sleep: 10s
current time:: 2011-Dec-12 12:21:16.090885
current time:: 2011-Dec-12 12:21:18.106295
current time:: 2011-Dec-12 12:21:20.106476
current time:: 2011-Dec-12 12:21:22.106648
current time:: 2011-Dec-12 12:21:24.106809
interrupt thread t
main sleep: 10s
set timer running = false
จะสังเกตได้ว่าเธรด t จะถูกขัดจังหวะการทำงาน ส่งผลให้ไม่มีการแสดงข้อความวันและเวลาออกมาอีก
ข้อพึ่งระวัง เนื่องจาก boost::this_thread::sleep(sleep_time); มีการอิมพลิเมนท์ interrupt point เอาไว้ดังนั้นเราจึงสามารถหยุดการทำงานของเธรดได้หากเราใช้ sleep ซึ่งเป็นฟังก์ชันใน cstdlib แทนเธรดจะไม่ถูกอินเทอร์รัพท์และจะทำงานปรกติแทน
ทดลองเปลี่ยน boost::this_thread::sleep(sleep_time); ในบรรทัดที่ 23 เป็น sleep(sleep_time.total_seconds()); แทนแล้ว คอมไพล์และเรียกทำงานใหม่อีกครั้ง $ g++ test_interupt.cpp -lboost_thread -lboost_date_time
$ ./a.out
Construct Timer
main sleep: 10s
current time:: 2011-Dec-12 12:33:21.625318
current time:: 2011-Dec-12 12:33:23.625694
current time:: 2011-Dec-12 12:33:25.625857
current time:: 2011-Dec-12 12:33:27.626025
current time:: 2011-Dec-12 12:33:29.626215
interrupt thread t
main sleep: 10s
current time:: 2011-Dec-12 12:33:31.626383
current time:: 2011-Dec-12 12:33:33.626552
current time:: 2011-Dec-12 12:33:35.626737
current time:: 2011-Dec-12 12:33:37.626902
current time:: 2011-Dec-12 12:33:39.627088
set timer running = false
ความคิดเห็น
แสดงความคิดเห็น