सी ++ एक सक्रिय अपवाद के बिना कहा जाता है


94

मुझे थ्रेडिंग के साथ C ++ त्रुटि मिल रही है:

terminate called without an active exception
Aborted

यहाँ कोड है:

#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>

template<typename TYPE>
class blocking_stream
{
public:
    blocking_stream(size_t max_buffer_size_)
        :   max_buffer_size(max_buffer_size_)   
    {
    }

    //PUSH data into the buffer
    blocking_stream &operator<<(TYPE &other)
    {
        std::unique_lock<std::mutex> mtx_lock(mtx); 
        while(buffer.size()>=max_buffer_size)
            stop_if_full.wait(mtx_lock);

        buffer.push(std::move(other));

        mtx_lock.unlock();
        stop_if_empty.notify_one();
        return *this;
    }
    //POP data out of the buffer 
    blocking_stream &operator>>(TYPE &other)
    {
        std::unique_lock<std::mutex> mtx_lock(mtx);
        while(buffer.empty())
            stop_if_empty.wait(mtx_lock);

        other.swap(buffer.front()); 
        buffer.pop();

        mtx_lock.unlock();
        stop_if_full.notify_one();
        return *this;
    }

private:
    size_t max_buffer_size;
    std::queue<TYPE> buffer;
    std::mutex mtx;
    std::condition_variable stop_if_empty,
                            stop_if_full;
    bool eof;   
};

मैं इस उदाहरण के आसपास मेरी कोड मॉडलिंग: http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html

मैं क्या गलत कर रहा हूं और मैं त्रुटि कैसे ठीक करूं?


9
क्या आप joinअपने मुख्य कार्यक्रम में अपने सभी धागे हैं?
केरेक SB SB

हमें बाकी कोड दिखाएं।
मैट

2
@Kerrek आह हा ने इस समस्या को ठीक कर दिया है, मुझे नहीं पता कि हालांकि मैं निश्चित हूं कि मुख्य धागा श्रमिकों के समाप्त होने से पहले समाप्त नहीं हुआ था। क्या मेरे लॉकिंग अलोगोरिथम्स सही दिखते हैं?
111111 23

संकलन कोड जो समस्या को पुन: पेश करता है।
मार्टिन यॉर्क

3
रनटाइम जैसा लगता है कि इस मामले में एक बेहतर निदान जारी कर सकता है?
निमो

जवाबों:


127

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


1
"जब कोई थ्रेड ऑब्जेक्ट दायरे से बाहर हो जाता है और यह जुड़ने की स्थिति में होता है, तो कार्यक्रम समाप्त हो जाता है" क्या आप इस बारे में एक मृत सरल, प्रतिलिपि प्रस्तुत करने योग्य उदाहरण प्रदान कर सकते हैं? ओपी में उदाहरण थोड़ा जटिल है।
एलेक जैकबसन

1
और यह कथन इस उत्तर के विरोधाभासी लगता है: stackoverflow.com/a/3970921/148668
एलेक जैकबसन

5
@mangledorf: ध्यान दें कि वे aobut बूस्ट :: थ्रेड बात कर रहे हैं और मैं std :: थ्रेड के बारे में बात कर रहा हूँ। इन दोनों का अलग-अलग विनाश व्यवहार है। यह समिति का एक सचेत निर्णय था।
बार्टोज़ मिलवस्की

यदि आप इस मुद्दे पर साथ चलें तो क्या होगा std::async? आप वहां बनने वाले किसी भी धागे को कैसे जोड़ / अलग कर सकते हैं? ऐसा नहीं लगता है कि परिणामी भविष्य की प्रतीक्षा करना पर्याप्त होगा, क्योंकि यह कहता है कि धागा "संभावित रूप से थ्रेड पूल से हो सकता है", और भविष्य का इंतजार () वास्तव में एक थ्रेड को पूल में समाप्त करने का मतलब नहीं है (और वह नहीं होगा) 'थ्रेड सेंस पूल के लिए वैसे भी समझ में नहीं आता)।
जेसन सी

2
बस एक अद्यतन कि सी ++ 20 में, विध्वंसक में std::jthreadकॉल करेगा .join()(जैसा कि यह दायरे से बाहर जाता है)। मैं व्यक्तिगत रूप से बेहतर पसंद करता हूं क्योंकि यह RAII का बेहतर अनुसरण करता है।
पोइया

46

उस त्रुटि को कैसे पुन: पेश करें:

#include <iostream>
#include <stdlib.h>
#include <string>
#include <thread>
using namespace std;
void task1(std::string msg){
  cout << "task1 says: " << msg;
}
int main() { 
  std::thread t1(task1, "hello"); 
  return 0;
}

संकलित करें और चलाएं:

el@defiant ~/foo4/39_threading $ g++ -o s s.cpp -pthread -std=c++11
el@defiant ~/foo4/39_threading $ ./s
terminate called without an active exception
Aborted (core dumped)

आपको वह त्रुटि मिलती है क्योंकि आप अपने धागे से जुड़ते या अलग नहीं होते।

इसे ठीक करने का एक तरीका, धागे को इस तरह मिलाएं:

#include <iostream>
#include <stdlib.h>
#include <string>
#include <thread>
using namespace std;
void task1(std::string msg){
  cout << "task1 says: " << msg;
}
int main() { 
  std::thread t1(task1, "hello"); 
  t1.join();
  return 0;
}

फिर संकलित करें और चलाएं:

el@defiant ~/foo4/39_threading $ g++ -o s s.cpp -pthread -std=c++11
el@defiant ~/foo4/39_threading $ ./s
task1 says: hello

इसे ठीक करने का दूसरा तरीका, इसे इस तरह से अलग करें:

#include <iostream>
#include <stdlib.h>
#include <string>
#include <unistd.h>
#include <thread>
using namespace std;
void task1(std::string msg){
  cout << "task1 says: " << msg;
}
int main() 
{ 
     {

        std::thread t1(task1, "hello"); 
        t1.detach();

     } //thread handle is destroyed here, as goes out of scope!

     usleep(1000000); //wait so that hello can be printed.
}

संकलित करें और चलाएं:

el@defiant ~/foo4/39_threading $ g++ -o s s.cpp -pthread -std=c++11
el@defiant ~/foo4/39_threading $ ./s
task1 says: hello

C ++ थ्रेड को अलग करने और C ++ थ्रेड में शामिल होने पर पढ़ें।


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

17

एरिक लेसिंस्की और बार्टोज़ मिल्वस्की ने पहले ही जवाब दे दिया है। यहाँ, मैं इसे और अधिक शुरुआती दोस्ताना तरीके से प्रस्तुत करने का प्रयास करूँगा।

एक बार एक धागा एक दायरे के भीतर शुरू किया गया है (जो खुद एक धागा पर चल रहा है), किसी को स्पष्ट रूप से यह सुनिश्चित करना होगा कि धागा दायरे से बाहर जाने से पहले निम्न में से कोई एक होता है:

  • रनटाइम स्कोप से बाहर निकलता है, उसके बाद ही थ्रेड निष्पादित होता है। यह उस धागे के साथ जुड़कर हासिल किया जाता है। भाषा पर ध्यान दें, यह बाहरी दायरा है जो उस धागे से जुड़ता है।
  • रनटाइम थ्रेड को अपने आप चलाने के लिए छोड़ देता है। इसलिए, प्रोग्राम इस दायरे से बाहर निकल जाएगा, चाहे यह थ्रेड निष्पादित हो या न हो। यह धागा अपने आप ही निष्पादित और बाहर निकल जाता है। यह थ्रेड का पता लगाकर प्राप्त किया जाता है। उदाहरण के लिए, यह समस्या हो सकती है, यदि धागा उस बाहरी क्षेत्र में चर को संदर्भित करता है।

ध्यान दें, जब तक थ्रेड के साथ या अलग किया जाता है, तब तक यह अच्छी तरह से निष्पादित हो सकता है। अभी भी दोनों में से कोई भी कार्य स्पष्ट रूप से किया जाना चाहिए।


1

जब तक आपका कार्यक्रम मर जाता है, तब तक बिना थ्रेड के या थ्रेड में शामिल हुए, यह त्रुटि होगी। धागे को अलग करने और शामिल किए बिना, आपको धागा बनाने के बाद अंतहीन लूप देना चाहिए।

int main(){

std::thread t(thread,1);

while(1){}

//t.detach();
return 0;}

यह भी दिलचस्प है कि, सोने या लूपिंग के बाद, थ्रेड को अलग किया जा सकता है या शामिल हो सकता है। इस तरह से भी आपको यह त्रुटि नहीं मिलती है।

नीचे दिए गए उदाहरण से यह भी पता चलता है कि, तीसरा धागा मुख्य मृत्यु से पहले अपना काम नहीं कर सकता है। लेकिन यह त्रुटि तब भी नहीं हो सकती है, जब तक आप कोड में कहीं अलग करते हैं। तीसरा धागा 8 सेकंड के लिए सोता है लेकिन मुख्य 5 सेकंड में मर जाएगा।

void thread(int n) {std::this_thread::sleep_for (std::chrono::seconds(n));}

int main() {
std::cout << "Start main\n";
std::thread t(thread,1);
std::thread t2(thread,3);
std::thread t3(thread,8);
sleep(5);

t.detach();
t2.detach();
t3.detach();
return 0;}

1

वर्ष, धागा शामिल होना चाहिए ()। जब मुख्य बाहर निकलें


1
यह उत्तर संभवतः किसी अन्य उत्तर से जुड़ी टिप्पणी के अधिक अनुकूल है। और मुझे कहना होगा, स्टैक ओवरफ्लो में आपका स्वागत है!
कंटैंगो

0

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

निम्नानुसार, पहली कॉलिंग के बिना एक थ्रेड डिस्ट्रक्टर को कॉल करना (ज्वाइन करने के लिए इंतजार करना) या डिटैच को तुरंत कॉल करने के लिए ग्वारेंटेड है :: प्रोग्राम समाप्त करें और समाप्त करें।

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.