Std :: फ्लश कैसे काम करता है?


84

क्या कोई समझा सकता है (अधिमानतः सादे अंग्रेजी का उपयोग करके) कैसे std::flushकाम करता है?

  • यह क्या है?
  • आप एक धारा कब प्रवाहित करेंगे?
  • यह महत्वपूर्ण क्यों है?

धन्यवाद।

जवाबों:


137

चूंकि यह उत्तर नहीं दिया गया था कि क्या std::flush होता है, यहां वास्तव में यह क्या है, इसके बारे में कुछ विवरण है। std::flushएक जोड़तोड़ है , यानी, एक विशिष्ट हस्ताक्षर के साथ एक फ़ंक्शन। सरल शुरू करने के लिए, आप std::flushहस्ताक्षर होने के बारे में सोच सकते हैं

std::ostream& std::flush(std::ostream&);

वास्तविकता थोड़ी अधिक जटिल है, हालांकि (यदि आप रुचि रखते हैं, तो इसे नीचे भी समझाया गया है)।

इस रूप के ऑपरेटरों को लेने वाली स्ट्रीम क्लास ओवरलोड आउटपुट ऑपरेटरों, यानी, तर्क के रूप में एक जोड़तोड़ लेने वाला एक सदस्य फ़ंक्शन है। आउटपुट ऑपरेटर ऑब्जेक्ट के साथ मैनिपुलेटर को कॉल करता है:

std::ostream& std::ostream::operator<< (std::ostream& (*manip)(std::ostream&)) {
    (*manip)(*this);
    return *this;
}

यही है, जब आप std::flushएक के साथ "आउटपुट" करते हैं std::ostream, तो यह संबंधित फ़ंक्शन को कॉल करता है, अर्थात, निम्नलिखित दो कथन समतुल्य हैं:

std::cout << std::flush;
std::flush(std::cout);

अब, std::flush()अपने आप में काफी सरल है: यह सब करने के लिए कॉल है std::ostream::flush(), यानी, आप इस तरह से कुछ देखने के लिए इसके कार्यान्वयन की कल्पना कर सकते हैं:

std::ostream& std::flush(std::ostream& out) {
    out.flush();
    return out;
}

std::ostream::flush()समारोह तकनीकी रूप से कॉल std::streambuf::pubsync()धारा बफर बाहरी गंतव्य के लिए पात्रों बफ़रिंग और भेजने के पात्रों जब इस्तेमाल किया बफर अतिप्रवाह हैं या जब आंतरिक प्रतिनिधित्व के साथ समन्वयित की जानी चाहिए के लिए जिम्मेदार है: धारा बफर (यदि हो तो) जो धारा साथ जुड़ा हुआ है पर बाहरी गंतव्य, यानी, जब डेटा फ्लश किया जाना है। बाहरी गंतव्य के साथ सिंक करने वाली अनुक्रमिक धारा पर इसका मतलब है कि किसी भी बफर वर्ण को तुरंत भेजा जाता है। यही है, std::flushधारा बफर का उपयोग करके इसके आउटपुट बफर को फ्लश करने का कारण बनता है। उदाहरण के लिए, जब डेटा को कंसोल पर लिखा जाता है, निस्तब्धता के कारण कंसोल पर इस बिंदु पर वर्ण दिखाई देते हैं।

यह सवाल उठा सकता है: वर्ण तुरंत क्यों नहीं लिखे गए हैं? इसका सरल उत्तर यह है कि वर्ण लिखना आमतौर पर काफी धीमा होता है। हालाँकि, वर्णों की एक उचित मात्रा को लिखने में जितना समय लगता है, वह अनिवार्य रूप से सिर्फ एक जगह लिखने के समान है। वर्णों की मात्रा ऑपरेटिंग सिस्टम, फ़ाइल सिस्टम आदि की कई विशेषताओं पर निर्भर करती है, लेकिन अक्सर 4k वर्णों की तरह कुछ उसी समय में लिखे जाते हैं जैसे कि केवल एक वर्ण। इस प्रकार, बाहरी गंतव्य के विवरणों के आधार पर बफर का उपयोग करने से पहले उन्हें भेजने वाले पात्रों में बहुत बड़ा प्रदर्शन सुधार हो सकता है।

उपरोक्त को आपके तीन प्रश्नों में से दो का उत्तर देना चाहिए। शेष प्रश्न है: आप एक धारा कब प्रवाहित करेंगे? इसका उत्तर है: जब पात्रों को बाहरी गंतव्य पर लिखा जाना चाहिए! यह एक फ़ाइल लिखने के अंत में हो सकता है (किसी फ़ाइल को बंद करने से बफर को फ़्लश हो जाता है, हालाँकि) या उपयोगकर्ता इनपुट के लिए पूछने से पहले तुरंत ध्यान दें ( std::coutजब से 'डी' है ) पढ़ते समय स्वचालित रूप से फ्लश हो std::cinजाता std::coutहै । हालांकि कुछ अवसर हो सकते हैं जहां आप स्पष्ट रूप से एक धारा प्रवाहित करना चाहते हैं, मुझे लगता है कि वे काफी दुर्लभ हैं।std::istream::tie()std::cin

अंत में, मैंने std::flushवास्तव में क्या है की एक पूरी तस्वीर देने का वादा किया : धाराएं वर्ग टेम्पलेट हैं जो विभिन्न चरित्र प्रकारों से निपटने में सक्षम हैं (व्यवहार में वे साथ काम करते हैं charऔर wchar_t, उन्हें अन्य पात्रों के साथ काम करना काफी शामिल है, हालांकि यदि आप वास्तव में निर्धारित हैं तो उल्लेखनीय है )। std::flushधाराओं के सभी तात्कालिक उपयोगों के साथ उपयोग करने में सक्षम होने के लिए , यह इस तरह के हस्ताक्षर के साथ एक फ़ंक्शन टेम्पलेट होता है:

template <typename cT, typename Traits>
std::basic_ostream<cT, Traits>& std::flush(std::basic_ostream<cT, Traits>&);

इसका std::flushतुरंत उपयोग के साथ उपयोग करने पर std::basic_ostreamवास्तव में कोई फर्क नहीं पड़ता: संकलक टेम्पलेट तर्कों को स्वचालित रूप से घटा देता है। हालाँकि, ऐसे मामलों में जहां टेम्पलेट फ़ंक्शन में कटौती की सुविधा के साथ इस फ़ंक्शन का उल्लेख नहीं किया गया है, कंपाइलर टेम्पलेट तर्क को कम करने में विफल हो जाएगा।


3
शानदार जवाब। गुणवत्ता की जानकारी नहीं मिल सकी कि फ्लश ने कहीं और कैसे काम किया।
माइकल

31

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

उदाहरण के लिए, मान लें कि आप किसी एकल बिंदु को प्रिंट करके प्रगति रिपोर्ट देना चाहते हैं:

for (;;)
{
    perform_expensive_operation();
    std::cout << '.';
    std::flush(std::cout);
}

फ्लशिंग के बिना, आप बहुत लंबे समय तक आउटपुट नहीं देखेंगे।

ध्यान दें कि std::endlएक धारा में एक नई रेखा सम्मिलित करता है और साथ ही साथ इसे प्रवाहित करता है। चूंकि निस्तब्धता काफी महंगी है, इसलिए std::endlअत्यधिक उपयोग नहीं किया जाना चाहिए अगर फ्लशिंग स्पष्ट रूप से वांछित नहीं है।


7
पाठकों के लिए बस एक अतिरिक्त नोट: coutकेवल वही चीज नहीं है जो C ++ में दी गई है। ostreamआमतौर पर s डिफ़ॉल्ट रूप से बफ़र किए जाते हैं, जिसमें fstreams और like भी शामिल होते हैं।
कॉर्नस्टॉक

इसके अलावा cinआउटपुट का उपयोग करने से पहले इसे फ्लश किया जाना चाहिए, नहीं?
ज़ैद खान

21

यहां एक छोटा कार्यक्रम है जिसे आप यह देखने के लिए लिख सकते हैं कि फ्लश क्या कर रहा है

#include <iostream>
#include <unistd.h>

using namespace std;

int main() {

    cout << "Line 1..." << flush;

    usleep(500000);

    cout << "\nLine 2" << endl;

    cout << "Line 3" << endl ;

    return 0;
}

इस प्रोग्राम को चलाएं: आप देखेंगे कि यह लाइन 1 को प्रिंट करता है, पॉज़ करता है, फिर लाइन 2 और 3 को प्रिंट करता है। अब फ़्लश कॉल को हटा दें और प्रोग्राम को फिर से चलाएं- आप देखेंगे कि प्रोग्राम पॉज़ हो गया और फिर सभी 3 लाइनों को प्रिंट करता है उसी समय। कार्यक्रम को रोकने से पहले पहली पंक्ति को बफ़र किया जाता है, लेकिन क्योंकि बफर को कभी भी फ्लश नहीं किया जाता है, पंक्ति 1 को तब तक आउटपुट नहीं किया जाता है जब तक कि लाइन 2 से एंडल कॉल न हो।


इसका वर्णन करने का एक और तरीका है cout << "foo" << flush; std::abort();। यदि आप टिप्पणी करते हैं / हटाते हैं << flush, तो कोई परिणाम नहीं है! पुनश्च: मानक-डीबगिंग डीएलएल जो कॉल abortएक बुरा सपना है। DLL को कभी भी कॉल नहीं करना चाहिए abort
मार्क स्टॉपर

5

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

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

मुझे यह उल्लेख करना चाहिए कि ओएस ड्राइवर लिखने वाले लोग या डिस्क ड्राइव डिजाइन करने वाले लोग सुझाव के रूप में 'फ्लश' का उपयोग करने के लिए स्वतंत्र हैं और वे वास्तव में वर्णों को नहीं लिख सकते हैं। यहां तक ​​कि जब आउटपुट बंद हो जाता है, तो उन्हें बचाने के लिए थोड़ी देर इंतजार करना पड़ सकता है। (याद रखें कि ओएस एक ही समय में सभी प्रकार की चीजें करता है और आपके बाइट्स को संभालने के लिए एक या दो इंतजार करना अधिक कुशल हो सकता है।)

इसलिए फ्लश एक प्रकार की चौकी है।

एक और उदाहरण: यदि आउटपुट कंसोल डिस्प्ले में जा रहा है, तो फ्लश यह सुनिश्चित करेगा कि अक्षर वास्तव में सभी तरह से बाहर निकलते हैं जहां उपयोगकर्ता उन्हें देख सकता है। यह एक महत्वपूर्ण बात है जब आप कीबोर्ड इनपुट की उम्मीद कर रहे हैं। अगर आपको लगता है कि आपने कंसोल पर एक प्रश्न लिखा है और यह अभी भी किसी आंतरिक बफर में कहीं अटक गया है, तो उपयोगकर्ता को यह नहीं पता है कि उत्तर में क्या लिखना है। तो, यह एक ऐसा मामला है जहां फ्लश महत्वपूर्ण है।

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