कैसे जांच करें कि क्या एक std :: धागा अभी भी चल रहा है?


84

अगर std::threadअभी भी चल रहा है (एक प्लेटफ़ॉर्म स्वतंत्र तरीके से) मैं कैसे जांच सकता हूं ? यह एक timed_join()विधि का अभाव है और उसके joinable()लिए नहीं है।

मैंने std::lock_guardथ्रेड में एक म्यूटेक्स को लॉक करने के बारे में सोचा और म्यूटेक्स की try_lock()विधि का उपयोग करके यह निर्धारित करने के लिए कि क्या यह अभी भी बंद है (थ्रेड चल रहा है), लेकिन यह मुझे अनावश्यक रूप से जटिल लगता है।

क्या आप एक अधिक सुंदर विधि जानते हैं?

अपडेट: स्पष्ट होने के लिए: मैं यह जांचना चाहता हूं कि धागा सफाई से बाहर निकला है या नहीं। इस उद्देश्य के लिए एक 'लटके' धागे को चालू माना जाता है।


मुझे लगता है कि यदि कोई थ्रेड अभी भी केवल तभी चल रहा है, जब आप wait()इसके लिए उम्मीद करते हैं और यदि ऐसा है, तो यदि आपने इसके wait()लिए अभी तक एड नहीं किया है, तो वह परिभाषा के अनुसार चलना चाहिए। लेकिन यह तर्क अक्षम हो सकता है।
ेरेऑन

वास्तव में मेरे पास एक धागा है जो असाधारण स्थितियों से बाहर निकलता है, और मैं मुख्य धागे से जांच करना चाहता हूं कि क्या यह अभी भी चल रहा है, लेकिन इसके लिए इंतजार नहीं करना चाहते (इसमें शामिल हों)
kispaljr

1
वास्तव में दौड़ने से आपका क्या मतलब है? क्या आपका मतलब है कि यह प्रतीक्षा की स्थिति में सक्रिय रूप से प्रसंस्करण कर रहा है, या क्या आपका मतलब है कि धागा अभी भी मौजूद है और समाप्त नहीं हुआ है?
कैशबैक

आप हमेशा बूस्ट का उपयोग कर सकते हैं :)
CashCow

4
यदि आप इससे संतुष्ट नहीं थे, तो आपको उत्तर स्वीकार नहीं करना चाहिए था।
निकोल बोलस

जवाबों:


117

यदि आप C ++ 11 का उपयोग करने std::asyncऔर std::futureअपने कार्यों को चलाने के लिए तैयार हैं, तो आप यह जांचने wait_forके std::futureलिए फ़ंक्शन का उपयोग कर सकते हैं कि क्या थ्रेड अभी भी इस तरह से चल रहा है:

#include <future>
#include <thread>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    /* Run some task on new thread. The launch policy std::launch::async
       makes sure that the task is run asynchronously on a new thread. */
    auto future = std::async(std::launch::async, [] {
        std::this_thread::sleep_for(3s);
        return 8;
    });

    // Use wait_for() with zero milliseconds to check thread status.
    auto status = future.wait_for(0ms);

    // Print status.
    if (status == std::future_status::ready) {
        std::cout << "Thread finished" << std::endl;
    } else {
        std::cout << "Thread still running" << std::endl;
    }

    auto result = future.get(); // Get result.
}

यदि आपको उपयोग करना चाहिए std::threadतो आप std::promiseभविष्य की वस्तु प्राप्त करने के लिए उपयोग कर सकते हैं :

#include <future>
#include <thread>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    // Create a promise and get its future.
    std::promise<bool> p;
    auto future = p.get_future();

    // Run some task on a new thread.
    std::thread t([&p] {
        std::this_thread::sleep_for(3s);
        p.set_value(true); // Is done atomically.
    });

    // Get thread status using wait_for as before.
    auto status = future.wait_for(0ms);

    // Print status.
    if (status == std::future_status::ready) {
        std::cout << "Thread finished" << std::endl;
    } else {
        std::cout << "Thread still running" << std::endl;
    }

    t.join(); // Join thread.
}

ये दोनों उदाहरण आउटपुट देंगे:

Thread still running

यह निश्चित रूप से है क्योंकि कार्य समाप्त होने से पहले थ्रेड स्थिति की जाँच की जाती है।

लेकिन फिर से, यह सरल हो सकता है जैसे कि दूसरों ने पहले ही उल्लेख किया है:

#include <thread>
#include <atomic>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    std::atomic<bool> done(false); // Use an atomic flag.

    /* Run some task on a new thread.
       Make sure to set the done flag to true when finished. */
    std::thread t([&done] {
        std::this_thread::sleep_for(3s);
        done = true;
    });

    // Print status.
    if (done) {
        std::cout << "Thread finished" << std::endl;
    } else {
        std::cout << "Thread still running" << std::endl;
    }

    t.join(); // Join thread.
}

संपादित करें:

std::packaged_taskउपयोग करने की std::threadतुलना में क्लीनर समाधान के लिए उपयोग के लिए भी है std::promise:

#include <future>
#include <thread>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    // Create a packaged_task using some task and get its future.
    std::packaged_task<void()> task([] {
        std::this_thread::sleep_for(3s);
    });
    auto future = task.get_future();

    // Run task on new thread.
    std::thread t(std::move(task));

    // Get thread status using wait_for as before.
    auto status = future.wait_for(0ms);

    // Print status.
    if (status == std::future_status::ready) {
        // ...
    }

    t.join(); // Join thread.
}

2
अच्छा जवाब। मैं
जोड़ूंगा

इस कोड का कारण क्या है std::atomic<bool> done(false);? क्या boolडिफ़ॉल्ट रूप से परमाणु नहीं है ?
हाय-एंजेल

6
@YagamyLight C ++ में कुछ भी डिफ़ॉल्ट रूप से परमाणु नहीं है जब तक कि यह एक में लिपटा न हो std::atomicsizeof(bool)कार्यान्वयन को परिभाषित किया गया है और> 1 हो सकता है, इसलिए यह संभव है कि आंशिक लेखन हो सकता है। वहाँ भी कैश सुसंगतता का मुद्दा है ..
सांप


1
ध्यान दें कि std :: chrono_literals को संकलन करने के लिए C ++ 14 की आवश्यकता होगी
Patrizio Bertoni

6

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

एक अधिक थ्रेड-सुरक्षित तरीका एक काउंटर है जो चाइल्ड थ्रेड द्वारा बढ़ाया जाता है, और मुख्य थ्रेड काउंटर को एक संग्रहीत मूल्य से तुलना करता है और यदि बहुत लंबे समय के बाद भी ऐसा ही है तो बच्चे के थ्रेड को सक्रिय नहीं माना जाता है।

ध्यान दें, वास्तव में मारने या हटाने वाले धागे को हटाने के लिए C ++ 11 में कोई रास्ता नहीं है।

संपादित करें कि कैसे जांच करें कि क्या एक धागा साफ निकला है या नहीं: मूल रूप से पहले पैराग्राफ में वर्णित तकनीक के समान है; एक बूलियन वैरिएबल को गलत के लिए इनिशियलाइज़ किया गया है। आखिरी बात जो बच्चा धागा करता है, वह उसे सच करता है। मुख्य धागा तब उस चर की जांच कर सकता है, और अगर सच है कि बच्चे के धागे पर बहुत कुछ (यदि कोई हो) बिना अवरोध के शामिल हो।

Edit2 यदि थ्रेड अपवाद के कारण बाहर निकलता है, तो दो थ्रेड "मुख्य" फ़ंक्शन हैं: पहले वाले में एक try- एक catchहै जिसके अंदर यह दूसरा "वास्तविक" मुख्य थ्रेड फ़ंक्शन कहता है। यह पहला मुख्य फ़ंक्शन "has_exited" चर सेट करता है। कुछ इस तरह:

bool thread_done = false;

void *thread_function(void *arg)
{
    void *res = nullptr;

    try
    {
        res = real_thread_function(arg);
    }
    catch (...)
    {
    }

    thread_done = true;

    return res;
}

1
यदि वह ओपी "रनिंग" की परिभाषा है।
कैशबैक

शायद आपने मुझे गलत समझा। मैं यह जांचना चाहता हूं कि क्या एक धागा सफाई से बाहर निकला है या नहीं। अस्पष्ट शब्दों के लिए क्षमा करें।
किस्पलज्र

7
यदि अलग-अलग धागे पढ़ रहे हैं और लिख रहे हैं thread_done, तो यह कोड मेमोरी बैरियर के बिना टूट गया है। std::atomic<bool>इसके बजाय उपयोग करें ।
.िलजार्नर

1
मैं कई कार्यकर्ता थ्रेड्स का जिक्र नहीं कर रहा था, मैं एक ही वर्कर थ्रेड राइटिंग का जिक्र कर रहा था boolजबकि मुख्य थ्रेड इसे पढ़ता है - इसके लिए मेमोरी बैरियर की जरूरत होती है।
.लडजर्न

3
चर्चा के लिए इस प्रश्न की जाँच करें std::atomic<bool>कि यहाँ क्यों आवश्यक है।
रॉबर्ट रूगर

3

इस सरल तंत्र को आप सम्मिलित विधि में अवरुद्ध किए बिना किसी धागे के परिष्करण का पता लगाने के लिए उपयोग कर सकते हैं।

std::thread thread([&thread]() {
    sleep(3);
    thread.detach();
});

while(thread.joinable())
    sleep(1);

2
धागे को अलग करना आखिरकार वह नहीं है जो कोई चाहता है, और यदि आप नहीं करते हैं, तो आपको join()कुछ ऐसे धागे से कॉल करना होगा जो अपनी joinable()संपत्ति को ढीला करने के लिए इंतजार नहीं करता है , अन्यथा यह अंतहीन रूप से लूप करेगा (यानी joinable()जब तक कि धागा वास्तव में सही न हो जाए join()ed और उसके समाप्त होने तक नहीं)
निकल्स R

joinable का मतलब है कि एक धागा एक धागा संभाल रहा है। यदि धागा किया जाता है, तो यह अभी भी शामिल हो जाएगा। यदि आपको थ्रेड के अंत की प्रतीक्षा किए बिना जांच करने की आवश्यकता है, तो यहां समाधान है। यह कोड की कुछ पंक्तियाँ है। आपने इसे पहले क्यों नहीं आज़माया?
एवगेनी कारपोव

मैंने किया था, और मैं जिस बिंदु को बनाने की कोशिश कर रहा हूं, वह यह है कि यदि आप thread.detach()भाग को हटा देते हैं , तो ऊपर दिया गया कार्यक्रम कभी समाप्त नहीं होगा।
आर

हाँ, यह नहीं होगा। यह क्यों अंत में कोचिंग बुला रहा है।
एवगेनी कारपोव

1
म्यूटेक्स और अन्य अधिक जटिल समाधानों की आवश्यकता के साथ टुकड़ी को कॉल करने की यह विधि। मैं इसका उपयोग करता हूं और यह काम करता है! जवाब के लिए धन्यवाद।
sep

1

एक म्यूटेक्स बनाएं जिसमें रनिंग थ्रेड और कॉलिंग थ्रेड दोनों की पहुंच हो। जब रनिंग थ्रेड शुरू होता है तो यह म्यूटेक्स को लॉक करता है, और जब यह समाप्त होता है तो म्यूटेक्स को अनलॉक करता है। यह जाँचने के लिए कि क्या थ्रेड अभी चल रहा है, कॉलिंग थ्रेड mutex.try_lock () को कॉल करता है। उस का रिटर्न मान थ्रेड की स्थिति है। (यदि try_lock काम किया है तो म्यूटेक्स को अनलॉक करना सुनिश्चित करें)

इसके साथ एक छोटी सी समस्या, mutex.try_lock () थ्रेड के निर्माण के समय के बीच झूठी वापस आ जाएगी, और जब यह म्यूटेक्स को लॉक करता है, लेकिन इससे थोड़ी अधिक जटिल विधि का उपयोग करके बचा जा सकता है।


-1 आपको std::mutexइस तरह के सिग्नलिंग के लिए उपयोग नहीं करना चाहिए (ज्यादातर कारणों से म्यूटेक्स आमतौर पर कैसे लागू किया जाता है)। एक atomic_flagकम भूमि के ऊपर जिस तरह से साथ इस मामले में बस के रूप में अच्छी तरह से काम करता है। एक std::futureऔर भी बेहतर हो सकता है के रूप में यह और अधिक स्पष्ट रूप मंशा व्यक्त करता है। इसके अलावा, याद रखें कि try_lockयह स्वाभाविक रूप से विफल हो सकता है, इसलिए वापसी आवश्यक रूप से धागे की स्थिति नहीं है (हालांकि यह शायद आपको इस विशेष मामले में बहुत चोट नहीं पहुंचाएगा)।
कॉमिकसंस

1

आप हमेशा जांच सकते हैं कि क्या थ्रेड की आईडी std :: थ्रेड :: id () डिफ़ॉल्ट रूप से निर्मित है। एक रनिंग थ्रेड में हमेशा एक वास्तविक संबद्ध आईडी होती है। बहुत अधिक फैंसी सामान से बचने की कोशिश करें :)


0

निश्चित रूप से एक म्यूटेक्स-लिपटे चर को इनिशियलाइज़ किया गया है false, जो कि trueनिकलने से पहले थ्रेड अंतिम चीज़ के रूप में सेट होता है। क्या वह परमाणु आपकी आवश्यकताओं के लिए पर्याप्त है?


1
यदि आप किसी भी तरह म्यूटेक्स का उपयोग करते हैं, तो मुझे लगता है कि मेरा समाधान (केवल म्यूटेक्स, डब्ल्यू / ओ बूलियन का उपयोग करके) अधिक सुरुचिपूर्ण होना चाहिए। यदि आप पूरी तरह से थ्रेड-सुरक्षित बूलियन का उपयोग करना चाहते हैं, तो मैं इसके बजाय std :: atomic <bool> सुझाऊंगा। अधिकांश कार्यान्वयनों में यह लॉक-फ़्री होगा।
किस्पलज्र

आखिर ताला क्यों? एक धागा केवल कभी पढ़ता है, एक केवल कभी लिखता है। और शब्द-आकार लिखते हैं किसी भी मामले में परमाणु IIRC।
XIO

1
@ Xeo: लेखन परमाणु हो सकता है, लेकिन एक मेमोरी बैरियर की अभी भी आवश्यकता है यदि आप एक अलग थ्रेड पर लिखित मूल्य (जो एक अलग सीपीयू पर निष्पादित हो सकता है) को देखने की उम्मीद करते हैं। std::atomic<bool>आपके लिए इस बात का ध्यान रखता है, यही वजह है कि इसका असली जवाब IMO है।
.िलजार्नर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.