मैं एक बूस्ट :: सिग्नल 2 सिग्नल के बहुप्रचारित आमंत्रणों को क्रमबद्ध करना चाहता हूं ताकि यह सुनिश्चित किया जा सके कि ऑब्जेक्ट से राज्य परिवर्तनों के बारे में अधिसूचनाएं एक अच्छी तरह परिभाषित क्रम में स्लॉट पर पहुंचें।क्या कोई बढ़ावा :: सिग्नल 2 सिग्नल के आमंत्रण क्रमबद्ध करने का कोई मौजूदा तरीका है?
पृष्ठभूमि
मैं एक बहु कार्यक्रम में एक आंतरिक स्थिति के साथ एक वस्तु है। आंतरिक स्थिति के कुछ हिस्सों कार्यक्रम के अन्य भागों के लिए दिलचस्प हैं, और वस्तु को बढ़ावा :: signals2 संकेत, इस के समान का उपयोग करके राज्य में परिवर्तन को उजागर करता है:
class ObjectWithState {
public:
enum State {
STATE_A,
STATE_B,
STATE_C,
};
void OnEvent() {
State newState;
{
boost::lock_guard<boost::mutex> lock(m_Mutex);
// Process event and change state
m_State = ...;
newState = m_State;
}
m_OnStateChanged(newState);
}
// method to allow external objects to connect to the signal etc
private:
boost::signals2::signal<void (State) > m_OnStateChanged;
boost::mutex m_Mutex;
State m_State;
};
समस्या
अगर वहाँ ऑनवेन्ट हैंडलर के कई समवर्ती आविष्कार हैं, यह संभावित रूप से परिवर्तनों की तुलना में श्रोताओं को दूसरे क्रम में राज्य परिवर्तनों के बारे में अधिसूचित किया जा सकता है। राज्य को ऊपर की तरह एक म्यूटेक्स द्वारा संरक्षित किया जाता है, इसलिए वास्तविक राज्य का स्वागत है। हालांकि, म्यूटेक्स को सिग्नल में कॉल के दौरान नहीं रखा जा सकता है, क्योंकि इससे डेडलॉक्स हो सकते हैं। इसका मतलब है कि सिग्नल का वास्तविक आविष्कार किसी भी क्रम में हो सकता है, जबकि मुझे उन्हें उसी क्रम में बुलाया जाना चाहिए क्योंकि राज्य में वास्तव में बदलाव हुए हैं।
इस समस्या को संभालने का एक तरीका सिग्नल से राज्य को हटाना होगा और सिर्फ श्रोताओं को सूचित करना होगा कि राज्य बदल गया है। फिर वे ऑब्जेक्ट को अपने राज्य के लिए पूछ सकते थे और राज्य को यह पता चल जाएगा कि जब ऑब्जेक्ट को या बाद में राज्य निकाल दिया गया था। मेरे परिदृश्य में, श्रोताओं को सभी राज्य परिवर्तनों के बारे में सूचित करने की आवश्यकता है, इसलिए यह विधि यहां काम नहीं करेगी।
मेरा अगला दृष्टिकोण की तरह कुछ होगा निम्नलिखित:
class ObjectWithState {
public:
enum State {
STATE_A,
STATE_B,
STATE_C,
};
void OnEvent() {
State newState;
boost::unique_future<void> waitForPrevious;
boost::shared_ptr<boost::promise<void> > releaseNext;
{
boost::lock_guard<boost::mutex> lock(m_Mutex);
// Process event and change state
m_State = ...;
newState = m_State;
waitForPrevious = m_CurrentInvocation->get_future();
m_CurrentInvocation.reset(new boost::promise<void>());
releaseNext = m_CurrentInvocation;
}
// Wait for all previous invocations of the signal to finish
waitForPrevious.get();
// Now it is our turn to invoke the signal
// TODO: use try-catch/scoped object to release next if an exception is thrown
OnStateChanged(newState);
// Allow the next state change to use the signal
releaseNext->set_value();
}
// method to allow external objects to connect to the signal etc
private:
boost::signals2::signal<void (State) > m_OnStateChanged;
boost::mutex m_Mutex;
State m_State;
// Initialized with a "fulfilled" promise in the constructor
// or do special handling of initially empty promise above
boost::shared_ptr<boost::promise<void> > m_CurrentInvocation;
};
मैं ऊपर कोड की कोशिश की है नहीं, तो यह कीड़े और संकलन त्रुटियों से अटे पड़े हो सकता है, लेकिन यह क्या निकालना संभव हो जाना चाहिए मैं बाद में हूँ मेरी आंत महसूस मुझे बताती है कि मैं इस प्रकार की समस्या का सामना करने वाला पहला व्यक्ति नहीं हूं और मैं अपने आप को कोशिश की गई और परीक्षण कोड का उपयोग करना पसंद करता हूं ... :) तो मेरा प्रश्न वास्तव में है:
क्या कोई पूर्ववर्ती तरीका है एक बढ़ावा के serialized invocations प्राप्त करने के लिए :: सिग्नल 2 सिग्नल (जैसे सिग्नल 2 पुस्तकालय या एक आम पैटर्न में बनाया गया)?
"हालांकि, म्यूटेक्स को सिग्नल पर कॉल में नहीं रखा जा सकता है, क्योंकि इससे डेडलॉक्स हो सकते हैं।" क्या आप इस पर स्पष्टीकरण दे सकते हैं? क्या कुछ सिग्नल हैंडलर 'ऑब्जेक्ट विथस्टेट' की स्थिति बदल सकते हैं? क्या वे नए 'ऑनवेन्ट()' कॉल जेनरेट करेंगे? आप कैसे सुनिश्चित करते हैं कि आप अनंत रिकर्सन में प्रवेश नहीं करते हैं? – user1202136
@ user1202136: हां। एक रिकर्सिव कॉल डेडलॉक पाने का एक तरीका होगा। एक और बेवकूफ तरीका यह है कि यदि आपके पास दो ऑब्जेक्ट विथस्टेट हैं और राज्य परिवर्तन के लिए हैंडलर सेट अप करते हैं, तो कुछ मामलों में दूसरे पर एक राज्य परिवर्तन ट्रिगर होता है। इससे पहले म्यूटेक्स को पकड़ने और दूसरे को लॉक करने की कोशिश करने वाले थ्रेड की ओर जाता है, और दूसरा धागा अन्य म्यूटेक्स को पकड़ता है और पहले लॉक करने की कोशिश करता है। अज्ञात कोड को कॉल करते समय एक सामान्य दिशानिर्देश लॉक को कभी नहीं पकड़ना है, चर्चा के लिए http://drdobbs.com/article/print?articleId=202802983&siteSectionName= देखें। – villintehaspam