2012-03-09 16 views
9

मेरे पास एक परिमित-राज्य मशीन का प्रतिनिधित्व करने वाली कक्षा है, जिसे हमेशा के लिए लूप में चलाना चाहिए और इसकी वर्तमान स्थिति की जांच करनी चाहिए। प्रत्येक राज्य मशीन में यह अगला राज्य सेट करेगा और या तो idle स्थिति में आ जाएगा या कुछ काम करेगा। मैं काम कर रहा है, जबकि मैं एक और थ्रेड मशीन की स्थिति बदलने की अनुमति देना चाहता हूँ। यह उम्मीद के रूप में दौड़ की स्थिति का कारण बन जाएगा। तो मैं मशीन के एक पारस्परिक बहिष्करण लॉक/अनलॉक रैपिंग लूप और सार्वजनिक विधि जो अन्य धागे को मशीन की वर्तमान स्थिति बदलने की अनुमति देता है।सी ++ में पारस्परिक बहिष्करण को संभालना 11

class Robot 
{ 
public: 
    enum StateType {s1,s2,s3,idle,finish}; 
    void run(); 
    void move(); 
private: 
    StateType currentState; 
    StateType nextState; 
    StateType previousState; 
    std::mutex mutal_state; 
}; 

कार्यान्वयन:

void Robot::run() 
{ 
    this->currentState = s1; 
    while(true) 
    { 
     mutal_state.lock(); 
     switch(currentState) 
     { 
     case s1: 
      // do some useful stuff here... 
      currentState = idle; 
      nextState = s3; 
      break; 
     case s2: 
      // do some other useful stuff here... 
      currentState = idle; 
      nextState = finish; 
      break; 
     case s3: 
      // again, do some useful things... 
      currentState = idle; 
      nextState = s2; 
      break; 
     case idle: 
      // busy waiting... 
      std::cout << "I'm waiting" << std::endl; 
      break; 
     case finish: 
      std::cout << "Bye" << std::endl; 
      mutal_state.unlock(); 
      return; 
     } 
     mutal_state.unlock(); 
    } 
} 

और कदम विधि है कि अन्य थ्रेड वर्तमान स्थिति को बदलने के लिए अनुमति देता है:

void Robot::move() 
{ 
    mutal_state.lock(); 
    previousState = currentState; // Booommm 
    currentState = nextState; 
    mutal_state.unlock(); 
} 

मैं मैं गलत क्या कर रहा लगाने के लिए प्रबंधन नहीं कर सकते! कार्यक्रम move() फ़ंक्शन की पहली पंक्ति में क्रैश हो जाता है। दूसरी ओर, GDB के साथ सी ++ 11 काम नहीं कर रहा है और पता लगाने कोड संभव नहीं है ...

अद्यतन:

कोड के आसपास बजाना, मैं देख सकता है कि समस्या कदम समारोह में है। जब प्रोग्राम move(), क्रैश के अंदर कोड टुकड़ा लॉक करने का प्रयास करता है। उदाहरण के लिए यदि इस कदम इस तरह है:

void Robot::move() 
{ 
    std::cout << "MOVE IS CALLED" << std::endl; 
    mutal_state.lock(); 
    //previousState = currentState; 
    //std::cout << "MOVING" << std::endl; 
    //currentState = nextState; 
    mutal_state.unlock(); 
} 

आउटपुट है:

s1 
I'm waiting 
I'm waiting 
MOVE IS CALLED1 
The program has unexpectedly finished. 

लेकिन जब move एक साधारण कार्य है, कुछ नहीं कर रहा है:

void Robot::move() 
{ 
    std::cout << "MOVE IS CALLED" << std::endl; 
    //mutal_state.lock(); 
    //previousState = currentState; 
    //std::cout << "MOVING" << std::endl; 
    //currentState = nextState; 
    //mutal_state.unlock(); 
} 

कार्यक्रम समवर्ती चलाता है।

+0

क्या आपने प्रिंट स्टेटमेंट्स के साथ डिबगिंग करने की कोशिश की है? – FrustratedWithFormsDesigner

+0

@ निराश WithFormsDesigner: हाँ। मुझे पता है कि "विस्फोट" केवल तभी होता है जब कुछ धागा 'चाल' को कॉल करने का प्रयास करता है। –

+0

आप किस कंपाइलर का उपयोग कर रहे हैं इसका संस्करण क्या है? – ildjarn

उत्तर

2

मेरे सुझाव:

1) यदि आप कोई डिबगर है, आप इसे कैसे कदम है कि दुर्घटनाओं की पहली पंक्ति है ताकि सुनिश्चित हो सकता है? कोड के बारे में आपके द्वारा किए गए किसी भी धारणा पर सवाल पूछना हमेशा होता है, जब तक कि आपके पास इसका समर्थन करने के लिए कठिन सबूत न हों।

2) मैं देखता हूं कि राज्य एस 3 में जो भी दिलचस्प कोड है, वही है जो चलने वाला पहला कॉल करेगा। उस बिंदु तक एस 3 में कोड चलाया नहीं गया है। या तो इसे रद्द करने के लिए पोस्ट किए गए उदाहरण में क्या है, सभी कोड बार को हटा दें या हटा दें।

3) कंपाइलर रजिस्टरों में चर के प्रतियां बना सकता है, आपको सभी राज्यों को अस्थिर के रूप में घोषित करना चाहिए ताकि यह इस तरह से अनुकूलित न हो।

2

मैं आपकी मदद नहीं कर सकता कि आपका कोड "विस्फोट" क्यों है, हालांकि मैं मान सकता हूं कि समस्या आपके द्वारा पोस्ट किए गए कोड में नहीं है क्योंकि यह मेरे लिए ठीक है। मेरे लिए

हो जाएगा ताकि उत्पादन:

I'm working 
... 
Bye 

कोड:

int main() { 

    Robot r; 

    auto async_moves = [&]() { // simulate some delayed interaction 
     std::this_thread::sleep_for(std::chrono::seconds(2)); //See note 
     for(auto i = 0; i != 3; ++i) 
      r.move(); 

    }; 

    auto handle = std::async(std::launch::async, async_moves); 

    r.run(); 

} 

(ध्यान दें: आप आप जीसीसी का उपयोग कर रहे संभालने -D_GLIBCXX_USE_NANOSLEEP साथ संकलित करने के लिए है, this प्रश्न देखें।)

ध्यान दें कि कोड ऊपर - और तुम्हारा शायद, बहुत - अभी भी समस्या का vulnurable कि राज्यों अगर move दो बार या एक से अधिक कहा जाता है से पहले पाश फिर से चलाता है अवैध हो सकती है।
टिप्पणियां पहले ही उल्लेख में से एक की तरह, lock_guards का उपयोग करना पसंद:

std::lock_guard<std::mutex> lock(mutal_state); 
+0

'std :: lock_guard' को आजमाने में मदद नहीं मिली। हालांकि मैं आपका कोड नहीं चला सकता। यह समाप्त हो जाता है: 'std :: system_error' का उदाहरण फेंकने के बाद बुलाया जाता है(): ऑपरेशन की अनुमति नहीं है ' –

+0

@ sorush-r आपको -pthread संकलक विकल्प जोड़ना होगा। वह उस त्रुटि को ठीक करेगा। – inf

+0

मैंने पहले से ही '-pthread' और' -lpthread' विकल्प दोनों जोड़े हैं। –

1

आप लिनक्स पर ++ जी का उपयोग कर रहे हैं, तो आप mutexes या ठीक से काम करने सामान सूत्रण के लिए क्रम में -lpthread साथ लिंक करना होगा। यदि आप नहीं करते हैं, तो यह लिंक करने में विफल नहीं होगा, लेकिन इसके बजाय रनटाइम पर बुरी तरह या दुर्घटनाग्रस्त हो जाएगा ...

+0

-pthread विकल्प का उपयोग करना शायद बेहतर है। यहां देखें: http://stackoverflow.com/q/2127797/893693। हालांकि, मुझे लगता है कि उसने वैसे भी किया था। – inf

+0

मैं '-pthread' और '-lpthread' लिंकर विकल्पों दोनों का उपयोग कर रहा हूं। जोड़ने के साथ कोई समस्या नहीं है। –

1

मैं अपना खुद का प्रश्न उत्तर दे रहा हूं! क्योंकि मुझे समस्या मिलती है, और यह लॉकिंग से संबंधित नहीं है और न ही C++ 0x के म्यूटेक्स कार्यान्वयन से संबंधित था। ImageProcess कक्षा है जो Robot की स्थिति को नियंत्रित करनी चाहिए। इसमें Robot* के माता-पिता के पॉइंटर हैं और इसका उपयोग करके move इसके माता-पिता होंगे। इसके लिए मैंने workhorse और start एर फ़ंक्शन लागू किया है। start एक std::tread spawns और उस पर workhorse चलाता है:

void ImageProcess::start() 
{ 
    std::thread x(&ImageProcess::workhorse, *this); 
    x.detach(); 
} 

मैंने महसूस किया कि workhorse में this->parent एक dangling सूचक है। जाहिर है parent->move() को क्रैश करना चाहिए। लेकिन यह तुरंत दुर्घटनाग्रस्त नहीं है! आश्चर्यजनक रूप से प्रोग्राम नियंत्रण move() फ़ंक्शन में प्रवेश करता है और फिर गैर-मौजूदा Robot चीज़ के previousState को बदलने का प्रयास करता है। (या गैर-मौजूदा Robot के म्यूटेक्स को लॉक करें)।

मुझे पता चला कि std::thread x(&ImageProcess::workhorse, *this); x.join() or x.detach() जैसे धागे का आविष्कार करते समय, कोड अब कॉलर ऑब्जेक्ट में नहीं चल रहा है। Robot::run() और ImageProcess::workhorse दोनों में this और &image का मुद्रित पता परीक्षण करने के लिए। अलग थे। मैं भी ImageProcess के लिए एक सार्वजनिक बूलियन foo जोड़ा गया है और Robot में true के मान में बदल गया है, तो workhorse और run में यह मुद्रित, workhorse मूल्य में हमेशा 0 है, लेकिन Robot में 1 है।

मेरा मानना ​​है कि यह बहुत अजीब व्यवहार है। मैं अगर यह स्मृति मॉडल या ImageProcess के मालिकाना हक किसी भी तरह std::thread x(&ImageProcess::workhorse, *this) के बाद बदल गया है करने के लिए संबंधित है पता नहीं ...

मैं ImageProcess एक कारखाने पैटर्न वर्ग बनाने (सब कुछ स्थिर है!)। अब ठीक है।