2012-09-13 12 views
13

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

तब मैंने सोचा है - हमम ... मान लें कि 100 सर्वर मेरे सर्वर-प्रोग्राम से कनेक्ट हैं, मैं उनमें से प्रत्येक के लिए 3 टाइमर बनाता हूं, इसलिए मैं 300 धागे चलाता हूं। क्या यह ज्यादा नहीं है? क्या यह ok है, कि मैं 300 धागे चलाता हूं?

तब मैं told था कि AS3 Timer मुख्य धागे में चलता है। और मैंने सोचा: कैसे ??? मैं मुख्य धागे में चलने वाले टाइमर को कैसे कार्यान्वित कर सकता हूं और इसे अवरुद्ध नहीं कर सकता? क्या यह सी ++ में संभव है?

+0

अधिकांश (या कम से कम से कम कई) टाइमर कार्यान्वयन वास्तव में अवरुद्ध कर रहे हैं। उसमें स्वाभाविक रूप से गलत कुछ भी नहीं है। यह स्पष्ट रूप से इस उद्देश्य पर निर्भर करता है। –

उत्तर

7

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

2

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

फिर टाइमर के लिए, एक चक्रीय टाइमर सेट करें, प्रत्येक 100 मिलीसेकंड (तदनुसार ट्यून करें) कहें। जब टाइमर समाप्त हो जाता है, तो पेड़ को हटाकर प्रत्येक क्लाइंट को प्रेषित कर दिया जाता है। जब आप क्लाइंट टाइमआउट तक पहुंचते हैं तो पुनरावृत्ति रोकना चाहिए जो अभी तक समाप्त नहीं हुआ है।

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

1

अब यह एक डिज़ाइन प्रश्न है, इसलिए सभी के पास अलग-अलग राय हैं और यह आपकी आवश्यकताओं पर भी निर्भर करता है, लेकिन आईएमओ, टाइमर को थ्रेडिंग नीति का निर्णय नहीं लेना चाहिए - क्लाइंट को ऐसा करना चाहिए।

मुझे यकीन नहीं है कि आप किस व्यवहार की अपेक्षा करते हैं, लेकिन यदि आप एक ही थ्रेड पर टाइमर पर 300 घटनाएं चलाते हैं और किसी कारण से एक ईवेंट हैंडलर ब्लॉक चलाते हैं, तो अन्य ईवेंट हैंडलर कभी ट्रिगर नहीं होंगे।

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

मैं दृढ़ता से सुझाव देता हूं कि प्रत्येक हैंडलर के लिए स्पष्ट नए धागे का उपयोग न करें, क्योंकि संदर्भ स्विचिंग प्रदर्शन को मारने की संभावना है। थ्रेड पूल इसे संतुलित करने में काफी बेहतर है।

1

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

यह भी मुख्य थ्रेड को अवरुद्ध करेगा जबकि कॉलबैक कोड निष्पादित किया जाएगा।

1

आपके पहले प्रश्न में पहले से ही पर्याप्त उत्तर हैं: टाइमर-ईवेंट (5 या 10 धागे का एक सेट) जो टाइमर घटनाओं को संभालने का सामान्य तरीका है और प्रत्येक घटना के लिए एक थ्रेड के बीच एक अच्छा समझौता है और एक सभी घटनाओं के लिए धागा।

अपने दूसरे प्रश्न के बारे में: नियमित कार्यक्रमों का उपयोग मतलब है कि आप मुख्य थ्रेड में टाइमर ईवेंट हैंडलर पर अमल नहीं कर सकते। यदि आप मुख्य धागे को "ब्लॉक" कर सकते हैं लेकिन मुख्य धागे में निष्पादित कोड से सहमति और समर्थन के बिना यह संभव नहीं है।

मुख्य थ्रेड समय-समय पर बंद करने के लिए और जाँच टाइमर से एक घटना है कि क्या वहाँ, एक वस्तु के रूप में टाइमर से पैरामीटर लेने के लिए और घटना को संभालने से होगा। इस सिद्धांत को डिजाइन करने के कई तरीके हैं लेकिन यह सामान्य तरीके हैं कि आप इसे कैसे करते हैं।

यूनिक्स प्रणालियों आप भी संकेतों का उपयोग कर के बारे में सोच सकता है पर, लेकिन मुझे विश्वास है कि कोई अच्छा विचार है।

1

आपके सर्वर सभी टाइमर के लिए एक टाइमर धागा चला सकते हैं। यह timer wheel ईवेंट बनाता है जब क्लाइंट टाइमर सर्वर टाइमर व्हील पर पंजीकृत होते हैं। जब पंजीकृत टाइमर का समय समाप्त हो जाता है, तो ईवेंट टाइमर व्हील द्वारा निर्धारित होता है। ग्राहक टाइमर पंजीकृत होने पर बनाए गए ईवेंट में हैंडल प्राप्त करते हैं। ग्राहक पंजीकृत टाइमर को समय-समय पर संकेत देने वाली घटनाओं की प्रतीक्षा कर सकते हैं। इस तरह धागा निर्माण ग्राहकों के लिए है।

0

आप सी ++ आपको लगता है कि के लिए Boost ASIO टाइमर का उपयोग कर सकते में रचना कर रहे हैं के बाद से। मैं भी एक टाइमर उन पर आधारित वर्ग तैयार किया गया है और यह अच्छी तरह से काम करता है और किसी भी धागे के बिना - यह ओएस के लिए अतुल्यकालिक कॉल का उपयोग करता है, तो मूल रूप से आप सिर्फ एक कॉलबैक जो जब घड़ी समाप्त हो रहा है बुलाया जाएगा परिभाषित करने के लिए और फिर घड़ी के कॉल async_wait फ़ंक्शन, जो गैर-अवरुद्ध है। जब आप अपना टाइमर ऑब्जेक्ट घोषित करते हैं तो आपको इसे io_service ऑब्जेक्ट पास करना होगा जो ओएसआई के लिए एएसआईओ इंटरफ़ेस है। यह ऑब्जेक्ट आपके एसिंक अनुरोधों और कॉलबैक की सेवा के लिए ज़िम्मेदार है, इसलिए इसके लिए आप अपनी अवरुद्ध विधि रन पर कॉल कर सकते हैं। मेरे मामले में मेरे पास मुख्य धागा अवरुद्ध नहीं हो सका, इसलिए मेरे पास सिर्फ एक धागा था जिसमें यह अनूठा कॉल अवरुद्ध हो रहा था।

यहाँ

आप कैसे बूस्ट ASIO async टाइमर का उपयोग करने के बारे में उदाहरण मिल सकते हैं:

http://www.boost.org/doc/libs/1_52_0/doc/html/boost_asio/tutorial/tuttimer2.html

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

abstractasiotimer.hpp:

#ifndef _ABSTRACTASIOTIMER_HPP_ 
#define _ABSTRACTASIOTIMER_HPP_ 

#include <boost/asio.hpp> 

/** 
* Encapsulates a POSIX timer with microsecond resolution 
*/ 
class AbstractAsioTimer 
{ 
    public: 
    /** 
    * Instantiates timer with the desired period 
    * @param io ASIO interface object to the SO 
    * @param timeout time in microseconds for the timer handler to be executed 
    */ 
    AbstractAsioTimer(boost::asio::io_service& io, unsigned int timeout); 

    /** 
    * Destructor 
    */ 
    virtual ~AbstractAsioTimer(); 

    /** 
    * Starts timer operation 
    */ 
    void timerStart(); 

    /** 
    * Stops timer operation 
    */ 
    void timerStop(); 

    /** 
    * Returns timer operation state 
    */ 
    bool isRunning() const; 

    /** 
    * Returns a reference to the underlying io_service 
    */ 
    boost::asio::io_service& get_io_service(); 

    protected: 
    /** 
    * Timer handler to execute user specific code 
    * @note must be reimplemented in derived classes 
    */ 
    virtual void onTimerTick() = 0; 

    private: 
    /** 
    * Callback to be executed on timer expiration. It is responsible 
    * for calling the 'onTimerTick' method and restart the timer if 
    * it remains active 
    */ 
    void timerExpired(const boost::system::error_code& error); 

    boost::asio::deadline_timer timer; /**< ASIO timer object */ 
    unsigned int timeout; /**< Timer period in microseconds */ 
    bool running; /**< Flag to indicate whether the timer is active */ 
}; 
#endif 

abstractasiotimer.cpp:

#include <iostream> 
#include <boost/bind.hpp> 
#include <boost/concept_check.hpp> 
#include "abstractasiotimer.hpp" 

using namespace boost::asio; 

AbstractAsioTimer::AbstractAsioTimer(boost::asio::io_service& io, 
            unsigned int timeout): 
            timer(io), timeout(timeout), 
            running(false) 
{ 

} 

AbstractAsioTimer::~AbstractAsioTimer() 
{ 
    running = false; 
    timer.cancel(); 
} 

void AbstractAsioTimer::timerExpired(const boost::system::error_code& error) { 

    if (!error) { 
    onTimerTick(); 
    //Restart timer 
    timerStart(); 
    } 
    else { 
    running = false; 
    std::cerr << "Timer stopped: " << error.message() << std::endl; 
    } 
} 

void AbstractAsioTimer::timerStart() 
{ 
    timer.expires_from_now(boost::posix_time::microseconds(timeout)); 
    timer.async_wait(boost::bind(&AbstractAsioTimer::timerExpired, 
        this, placeholders::error)); 
    running = true; 
} 

void AbstractAsioTimer::timerStop() { 
    running = false; 
    timer.cancel(); 
} 

bool AbstractAsioTimer::isRunning() const { 
    return running; 
} 

io_service& AbstractAsioTimer::get_io_service() 
{ 
    return timer.get_io_service(); 
} 
संबंधित मुद्दे