2013-11-21 18 views
6

में std :: थ्रेड निकास पर स्वचालित रूप से फ़ंक्शन को आमंत्रित करना मैं वर्तमान थ्रेड से बाहर होने पर स्वचालित रूप से होने के लिए फ़ंक्शन (या लैम्ब्डा फ़ंक्शन) का एक आमंत्रण सेट करना चाहता हूं, लेकिन मुझे ऐसा करने का कोई तरीका नहीं दिख रहा है यह std::thread के साथ काम करता है जब तक कि मैं थ्रेड सृजन का पूरा कार्य नहीं लेता या मैन्युअल रूप से यह सुनिश्चित करता हूं कि प्रत्येक थ्रेड कुछ विशेष फ़ंक्शन को कॉल करता है जिसे मैं हमेशा अपने अंतिम ऑपरेशन के रूप में प्रदान करता हूं।सी ++ 11

अनिवार्य रूप से, मैं समारोह जिसका प्रोटोटाइप कुछ इस तरह जैसे लगते हो सकता हैं:

on_thread_exit(const std::function<void()> &func); 

कौन सा प्रदर्शन करेंगे जो कुछ भी सेटअप सुनिश्चित करना है कि यह देखते हुए समारोह स्वचालित रूप से धागा जो on_thread_exit कहा जाता है अंत में समाप्त हो जाता है बुलाया गया था जरूरी हो गया था, और धागे निर्माण या समाप्ति पर स्पष्ट रूप से बुलाए जाने वाले किसी भी विशेष कार्यों की आवश्यकता के बिना।

+0

यह ऐसा मामला है जिस धागा कॉलबैक कॉल करता है? ट्रिगरिंग थ्रेड निकलने के तुरंत बाद, इसे एक सहायक थ्रेड द्वारा किया जा सकता है? –

उत्तर

19

आप इसे thread_local स्टोरेज का उपयोग करके कर सकते हैं, क्योंकि सी ++ 11 को धागे से बाहर निकलने के बाद विनाशकों को कॉल करना चाहिए। आपको यह सुनिश्चित करना होगा कि आपके पास एक कंपाइलर है जो ठीक से इसका समर्थन करता है।

#include <stack> 
#include <function> 

void on_thread_exit(std::function<void()> func) 
{ 
    class ThreadExiter 
    { 
    std::stack<std::function<void()>> exit_funcs; 
    public: 
    ThreadExiter() = default; 
    ThreadExiter(ThreadExiter const&) = delete; 
    void operator=(ThreadExiter const&) = delete; 
    ~ThreadExiter() 
    { 
     while(!exit_funcs.empty()) 
     { 
     exit_funcs.top()(); 
     exit_funcs.pop(); 
     } 
    } 
    void add(std::function<void()> func) 
    { 
     exit_funcs.push(std::move(func)); 
    } 
    }; 

    thread_local ThreadExiter exiter; 
    exiter.add(std::move(func)); 
} 

असल में, इस समारोह से ऊपर वर्ग के एक thread_local वस्तु बनाता है। यह मूल रूप से स्थैतिक है, सिगर को छोड़कर नष्ट हो जाता है। जब बुलाया जाता है, तो यह कार्य को वेक्टर पर धक्का देता है, और जब इसे नष्ट कर दिया जाता है तो यह कार्य चलाता है।

आप किसी भी थ्रेड से on_thread_exit() पर कॉल करके इसका उपयोग कर सकते हैं, जो एक्जिट ऑब्जेक्ट बना देगा, जो आपके फ़ंक्शन को रिवर्स ऑर्डर में चलाएगा जिसे इसे थ्रेड कतार में रखा गया था (जैसा कि आप फिट देखते हैं उसे संशोधित करने के लिए स्वतंत्र महसूस करें)।

+0

बहुत अच्छा समाधान। – Oakdale

+0

आप विनाशक को कोशिश/पकड़ना जोड़ सकते हैं क्योंकि संग्रहीत फ़ंक्शन फेंक सकता है –

1

आप मुख्य थ्रेड के लिए BOOST_SCOPE_EXIT

उपयोग कर सकते हैं:

void on_thread_exit(); 

void main(int argc, char** argv) 
{ 
    BOOST_SCOPE_EXIT() // may be one arg, at least, is required 
    { 
     on_thread_exit(); 
    }BOOST_SCOPE_EXIT_END 

    ... 
} 

मैं आप किसी भी धागा एक्सट्रपलेशन छोड़ दो!

4

यहाँ निम्नलिखित गुणों के साथ अधिक सी ++ 11 सुविधाओं का उपयोग करता है डेव एस के समाधान के आधार पर एक सरल/छोटा संस्करण है:

  • ThreadExiter के बाद से केवल एक बार प्रयोग किया जाता है, हम चर घोषणा गठजोड़ कर सकते हैं, से बचने public/private (struct-class) और प्रतिलिपि निर्माता/असाइनमेंट ऑपरेटर
  • बदलें साथ std::deque
  • पाश के लिए सीमा के आधार पर और std::stack हटाने सदस्य variabl में जोड़े ई सीधे कि इस नष्ट हो std::deque के कॉलबैक कार्यों के बाद ही सभी को बुलाया गया है, एक add() विधि होने

नोट के बदले जो हो सकता है या नहीं हो सकता है कि आप क्या चाहते हैं - यदि आप समारोह वस्तु की आवश्यकता होने के लिए इसे बुलाए जाने के बाद नष्ट कर दिया गया है (और किसी भी अन्य कार्य वस्तुओं को बुलाए जाने से पहले), डेव के समाधान में एक स्टैक और पॉप तत्वों का उपयोग करें)।

कोड:

#include <functional> 
#include <deque> 

void 
on_thread_exit(std::function<void()> func) 
{ 
    thread_local struct ThreadExiter { 
     std::deque<std::function<void()>> callbacks; 

     ~ThreadExiter() { 
      for (auto &callback: callbacks) { 
       callback(); 
      } 
     } 
    } exiter; 

    exiter.callbacks.emplace_front(std::move(func)); 
}