close up photo of programming of codes

codecungnhau.com

Một trang web về kỹ thuật lập trình

C++11 Multithreading – P.2: Joining và Detaching Threads

Joining Threads với std::thread::join()

Khi một thread được bắt đầu thì một thread khác có thể đợi thread mới này kết thúc. Để thực hiện điều này, ta cần gọi hàm join() trên đối tượng std::thread.

std::thread th(funcPtr);
// Some Code
th.join();

Hãy xem một ví dụ sau, giả sử thread main phải khởi chạy 10 thread Workder và sau khi bắt đầu tất cả các thread này, hàm main sẽ chờ chúng hoàn thành. Sau đó, hàm main sẽ tiếp tục công việc của nó.

#include <iostream>
#include <thread>
#include <algorithm>
class WorkerThread
{
public:
    void operator()()     
    {
        std::cout<<"Worker Thread "<<std::this_thread::get_id()<<" is Executing"<<std::endl;
    }
};
int main()  
{
    std::vector<std::thread> threadList;
    for(int i = 0; i < 10; i++)
    {
        threadList.push_back( std::thread( WorkerThread() ) );
    }
    // Now wait for all the worker thread to finish i.e.
    // Call join() function on each of the std::thread object
    std::cout<<"wait for all the worker thread to finish"<<std::endl;
    std::for_each(threadList.begin(),threadList.end(), std::mem_fn(&std::thread::join));
    std::cout<<"Exiting from Main Thread"<<std::endl;
    return 0;
}

Detaching Threads sử dụng std::thread::detach()

Thread detach còn được gọi là thread chạy nền (background thread).  Để detach một thread ta cần gội std::detach() trên đối tượng std::thread. Sau khi gọi detach(), đối tượng std::thread sẽ không còn liên kết với sự thực thi của thread đó nữa.

std::thread th(funcPtr);
th.detach();

Chú ý khi Join hoặc Detach một thread

Trường hợp 1: Đừng bao giờ gọi hàm join() hoặc detach() trên đối tượng std::thread mà không liên kết với thread đang thực thi nào cả.

std::thread threadObj( (WorkerThread()) );
threadObj.join();
threadObj.join(); // Nó sẽ gây ra lỗi Terminate cho chương trình

Khi một hàm join() hay detach() được gọi và sau khi trở về, đối tượng std::thread sẽ không còn liên kết với thread nữa. Do đó, nếu gọi một lần nữa nó sẽ gây ra lỗi Terminate.

Vì thế trước khi gọi các hàm này, ta cần kiểm tra xem thread có là join-ale hay không. Nếu có, ta có thể join hoặc detach thread đó.

 std::thread threadObj2( (WorkerThread()) );
 if(threadObj2.joinable())
 {
    std::cout<<"Joining Thread "<<std::endl;
    threadObj2.join();
}
if(threadObj2.joinable())    
{
    std::cout<<"Joining Thread "<<std::endl;
    threadObj2.join();
}

Trường hợp 2: Đừng quên gọi hàm join() hoặc detach() trên đối tượng std::thread mà có liên kết với thread đang thực thi.

Nếu không gọi hàm join() hoặc detach() trên đối tượng std::thread mà có liên kết với thread đang thực thi, thì trong quá trình hủy đối tượng này, nó sẽ kiểm tra xem thread có là join-able không. Nếu có, nó sẽ gây ra lỗi Terminate.

#include <iostream>
#include <thread>
#include <algorithm>
class WorkerThread
{
public:
    void operator()()     
    {
        std::cout<<"Worker Thread "<<std::endl;
    }
};
int main()  
{
    std::thread threadObj( (WorkerThread()) );
    // Chương trình sẽ bị terminate vì hàm join() hay detach() đã không được gọi cho đối tượng threadObj.
    // Do đó, hàm hủy của đối tượng std::thread sẽ ngắt chương trình.
    return 0;
}

Tương tự trong trường hợp xử lý ngoại lệ, ta cũng không được quên việc gọi join hoặc detach này.

#include <iostream>
#include <thread>
class ThreadRAII
{
    std::thread & m_thread;
    public:
        ThreadRAII(std::thread  & threadObj) : m_thread(threadObj)
        {
            
        }
        ~ThreadRAII()
        {
            // Kiểm tra nếu thread là joinable thì detach nó.
            if(m_thread.joinable())
            {
                m_thread.detach();
            }
        }
};
void thread_function()
{
    for(int i = 0; i < 10000; i++);
        std::cout<<"thread_function Executing"<<std::endl;
}
 
int main()  
{
    std::thread threadObj(thread_function);
    
    // Nếu ta comment line này, chương trình sẽ bị crash
    ThreadRAII wrapperObj(threadObj);
    return 0;
}

Đã đăng vào

trong

,

bởi

Bình luận

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *