2012-05-09 18 views
13

से पढ़ने के दौरान मैं पढ़ने के लिए टाइमआउट को कैसे कार्यान्वित कर सकता हूं, मैं फाइल डिस्क्रिप्टर और पॉज़िक्स/यूनिक्स रीड() फ़ंक्शन का उपयोग कर सी ++ में एक सीरियल पोर्ट से बाइट्स पढ़ रहा हूं। इस उदाहरण में, मैं सीरियल पोर्ट से 1 बाइट पढ़ रहा हूँ (बॉड दर सेटिंग्स और समान स्पष्टता के लिए छोड़े गए हैं): डिवाइस/dev/ttyS0 से जुड़े किसी भी जानकारी नहीं भेजतासीरियल पोर्ट (सी/सी ++)

#include <termios.h> 
#include <fcntl.h> 
#include <unistd.h> 

int main(void) 
{ 
    int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY); 
    char buf[1]; 
    int bytesRead = read(fd, buf, 1); 
    close(fd); 
    return 0; 
} 

, तो प्रोग्राम होगा लटका। मैं टाइमआउट कैसे सेट कर सकता हूं?

मैं इस तरह एक समय बाहर स्थापित की कोशिश की है:

struct termios options; 
tcgetattr(fd, &options); 
options.c_cc[VMIN] = 0; 
options.c_cc[VTIME] = 10; 
tcsetattr(fd, TCSANOW, &options); 

मैंने सोचा कि यह 1 सेकंड का समय समाप्त देना चाहिए था, लेकिन यह कोई फर्क नहीं पड़ता। मुझे लगता है कि मैंने वीएमआईएन और वीटीआईएमई को गलत समझा है। वीएमआईएन और वीटीआईएमई क्या उपयोग किया जाता है?

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

किसी भी मदद की सराहना की है। अग्रिम धन्यवाद :-)

+0

'tcsetattr का उपयोग करना()' 'VTIME' सरल नहीं है की; इसके लिए अन्य मोड सेटिंग्स की आवश्यकता होती है जो कुछ धारावाहिक ड्राइवर समर्थन नहीं करते हैं। एक सामान्य समाधान के लिए मेरा जवाब देखें। – wallyk

+0

यह सबसे अच्छा विवरण मैं vmin और VTIME [http://unixwiz.net/techtips/termios-vmin-vtime.html](http://unixwiz.net/techtips/termios- के लिए वेब पर का सामना करना पड़ा है vmin-vtime.html)। लेख के मुताबिक जब आईसीएएनओएन बिट बंद हो जाता है तो यह वीएमआईएन और वीटीआईएमई की व्याख्या को बदलने के लिए "कच्चा मोड" सक्षम बनाता है। आईसीएएनओएन बिट सेट करने से कोड को अपेक्षित काम मिल जाएगा। – arpl

उत्तर

16

हाँ, का उपयोग select(2)। फ़ाइल डिस्क्रिप्टर सेट में पास करें जिसमें केवल आपके एफडी को रीड सेट और रिक्त लेखन/अपवाद सेट में शामिल किया गया है, और उपयुक्त टाइमआउट में पास किया गया है। उदाहरण के लिए:

int fd = open(...); 

// Initialize file descriptor sets 
fd_set read_fds, write_fds, except_fds; 
FD_ZERO(&read_fds); 
FD_ZERO(&write_fds); 
FD_ZERO(&except_fds); 
FD_SET(fd, &read_fds); 

// Set timeout to 1.0 seconds 
struct timeval timeout; 
timeout.tv_sec = 1; 
timeout.tv_usec = 0; 

// Wait for input to become ready or until the time out; the first parameter is 
// 1 more than the largest file descriptor in any of the sets 
if (select(fd + 1, &read_fds, &write_fds, &except_fds, &timeout) == 1) 
{ 
    // fd is ready for reading 
} 
else 
{ 
    // timeout or error 
} 
+0

बहुत बहुत धन्यवाद। ऐसा लगता है जैसे मैं चाहता था। मेरे पास तीन और प्रश्न हैं: क्या मैं बंदरगाह खोलते समय टाइमआउट करने के लिए भी चयन कर सकता हूं? क्या मैं FD_SET (fd, और write_fds) सेट करके, लिखने के ऑपरेशन पर टाइमआउट के लिए एक ही कोड का उपयोग कर सकता हूं? और आखिरी: इसके अलावा इस्तेमाल किए गए_एफडीएस क्या है? – pvh1987

+2

मतदान() आमतौर पर चयन() से बेहतर है। –

+0

महान काम करता है! यदि मैं इसे लूप में चलाता हूं, तो क्या मुझे प्रत्येक पुनरावृत्ति में FD_ZERO और FD_SET की आवश्यकता है, या लूप ठीक होने से पहले एक बार है? – Andy

0

कई संभावित दृष्टिकोण हैं के रूप में इंटरनेट कि कैसे चुनें (उपयोग करने के लिए पर जानकारी दे देंगे) पर कई पृष्ठों, कर रहे हैं। यदि कार्यक्रम अंत में एक से अधिक I/o ऑपरेशन का समय लगेगा, select() स्पष्ट विकल्प है।

हालांकि, अगर एकमात्र इनपुट इस आई/ओ से है, तो गैर-अवरुद्ध I/o और समय चुनना एक सीधा तरीका है। मैं भी एक वर्ण से विस्तार किया है मैं/बहु चरित्र के लिए ओ यह एक अधिक आम तौर पर पूर्ण उदाहरण बनाने के लिए:

#include <fcntl.h> 
#include <termios.h> 
#include <unistd.h> 
#include <sys/time.h> 

int main(void) 
{ 
    int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY); // sometimes "O_NONBLOCK" 
    char buf[10]; 
    int done = 0, inbuf = 0; 
    struct timeval start, now; 

    gettimeofday (&start, NULL); 
    while (!done) 
    { 
     int bytesRead = read(fd, &buf[inbuf], sizeof buf - inbuf); 
     if (bytesRead < 0) 
     { 
      error_processing_here(); 
      continue; 
     } 
     if (bytesRead == 0) // no data read to read 
     { 
      gettimeofday (&now, NULL); 
      if ((now.tv.sec - start.tv_sec) * 1000000 + 
       now.tv.usec - start.tv_usec > timeout_value_in_microsecs) 
      { 
       done = 2; // timeout 
       continue; 
      } 
      sleep(1); // not timed out yet, sleep a second 
      continue; 
     } 
     inbuf += bytesRead; 
     if (we have read all we want) 
      done = 1; 
    } 
    if (done == 2) 
     timeout_condition_handling(); 
    close(fd); 
    return 0; 
} 
+0

यह चयन() का उपयोग करने से बहुत अधिक कोड है, और पढ़ने से पहले डेटा उपलब्ध होने के बाद एक सेकंड तक प्रतीक्षा कर सकता है। –

+0

@ MartinC.Martin: ठीक है, यह क्योंकि मेरे कोड एक पूरा काम कर उदाहरण पढ़ने और त्रुटि जाँच जबकि चुनिंदा उदाहरण क्या जरूरत होगी की ही टुकड़ा दिखाई दे रहा है सहित है कि जिस तरह से लग सकता है। – wallyk

+0

1 सेकंड नींद (विशेष रूप से उच्च बॉड दरों में) के दौरान डेटा की भीड़ हो सकती है, इसलिए नींद का उपयोग करना अच्छा नहीं है। छोटी नींद प्रोसेसर समय को भी बर्बाद कर सकती है जो कम संचालित उपकरणों में अधिक मायने रखती है। इस कोड को 'चयन' का उपयोग करके गैर-मतदानकारी ऐप्लिकेशन ले कर सुधार किया जा सकता है। – Isaac

1

आप पर कब्जा संकेत प्रयास आपरेशन पढ़ को रोकने के लिए कर सकते हैं। (1) पढ़ने से पहले अलार्म का उपयोग, और अगर पढ़ा समारोह लौटे नहीं किया, अलार्म SIGALRM संकेत भेज देंगे, तो आप इस संकेत पर कब्जा करने, इस तरह सिग्नल प्रोसेसिंग समारोह बना सकते हैं:

#include <stdio.h> 
#include <stdlib.h> 
#include <signal.h> 
#include <setjmp.h> 

static jmp_buf env_alarm; 

static void sig_alarm(int signo) 
{ 
    longjmp(env_alarm, 1); 
} 

int main(void) 
{ 
    int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY); 
    char buf[1]; 

    if (signal(SIGALRM, sig_alarm) == SIG_ERR) 
    { 
     exit(0); 
    } 

    if (setjmp(env_alarm) != 0) 
    { 
     close(fd); 
     printf("Timeout Or Error\n"); 
     exit(0); 
    } 

    alarm(1); 
    int bytesRead = read(fd, buf, 1); 
    alarm(0); 

    close(fd); 
    return 0; 
} 

लेकिन चयन का उपयोग करें या पोल या यदि आपका कार्यक्रम बड़ा है तो एपोल बेहतर होगा।

+0

वहाँ के बारे में चयन एक दिलचस्प मामला है, यह जाँच fd बारे में हो सकता है लेकिन यह ब्लॉक जब लिखने हो जाएगा, तो मैं चयन विधि मेरे मामले में ठीक नहीं काम करता है सकते हैं लगता है, लेकिन अपने विधि ठीक काम करता है सकते हैं। यह एक अच्छी विधि है। – kangear

1

वीएमआईएन और वीटीएमई क्या उपयोग किया जाता है?

यदि MIN> 0 और TIME = 0, MIN पढ़ने से पहले प्राप्त करने के लिए वर्णों की संख्या सेट करता है। जैसे ही समय शून्य है, टाइमर का उपयोग नहीं किया जाता है।

यदि MIN = 0 और TIME> 0, TIME टाइमआउट मान के रूप में कार्य करता है। पढ़ा जाएगा संतुष्ट हो यदि एक वर्ण पढ़ा जाता है, या समय पार हो जाता है (टी = समय * 0.1 एस)। यदि समय पार हो गया है, तो कोई चरित्र वापस नहीं किया जाएगा।

यदि MIN> 0 और TIME> 0, TIME अंतर-वर्ण टाइमर के रूप में कार्य करता है। पढ़ने संतुष्ट हो सकता है अगर MIN वर्ण प्राप्त कर रहे हैं, या समय दोनों के बीच वर्ण समय से अधिक है। टाइमर हर बार एक चरित्र प्राप्त होता है पुन: प्रारंभ होने और केवल सक्रिय हो जाता है के बाद पहली चरित्र प्राप्त हो गया है।

मिन = 0 और समय = 0, तो पढ़ तुरंत संतुष्ट हो जाएगा। वर्तमान में उपलब्ध वर्णों की नंबर, या वर्ण अनुरोध किया की संख्या लौटा दी जाएगी। एंटोनिनो के अनुसार (योगदान देखें), आप एक fcntl (fd, F_SETFL, FNDELAY) जारी कर सकते हैं; एक ही परिणाम प्राप्त करने के लिए पढ़ने से पहले।

स्रोत: http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html

संबंधित मुद्दे