2012-10-06 65 views
5

संभव डुप्लिकेट:
Loops/timers in Cटाइमर

मैं पिछले 3 दिनों के लिए टाइमर के बारे में पढ़ रहा था और मैं कुछ भी उपयोगी खोजने में असमर्थ हूँ, मैं मैं इसे वास्तविक उदाहरण में समझने की कोशिश कर रहा हूं, क्या कोई मुझे नीचे प्रोग्राम के लिए अलार्म सेट करने का तरीका जानने में मदद कर सकता है।

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

कृपया ध्यान दें कि पर्यावरण लिनक्स है, और मैं एक कामकाजी सी उदाहरण के साथ किसी भी लिंक की सराहना करता हूं।

#include<stdio.h> 
int delete_from_array(int arg) ; 


    int main() 
    { 

    int a[10000], i, y ; 
    //how to set timer here for to delete any number in array after half a second 
    for (y=0; y < 100; y++) { 


     for (i=0; i<sizeof(a)/sizeof(int); i++) 
      a[i] = i; 
    sleep(1); 
    printf("wake\n"); 
    } 

    } 

    int delete_from_array(int arg) 
    { 
    int i, a[1000], number_to_delete=0; 

    //number_to_delete = arg->number; 

    for (i=0; i<sizeof(a); i++) 
     if (a[i] == number_to_delete) 
      a[i] = 0; 
    printf("deleted\n"); 

    } 

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

+0

यह 'i

+2

आप [this] (http://stackoverflow.com/questions/5540245/loops-timers-in-c) प्रश्न – tomahh

+0

मेरी गलती को देखना चाहते हैं, मेरा मतलब है आकार (ए)/आकार (int), मैं कोड संशोधित करें। –

उत्तर

19

में रीट्रान्समिशन की तरह आप संकेत या धागे का उपयोग करना चाहते हैं?

सबसे पहले, सिग्नल हैंडलर सेट करें या उपयुक्त थ्रेड फ़ंक्शन तैयार करें; विवरण के लिए man 7 sigevent देखें।

अगला, timer_create() का उपयोग करके एक उपयुक्त टाइमर बनाएं। विवरण के लिए man 2 timer_create देखें।

टाइमर आग लगने पर आप जो करते हैं उसके आधार पर, आप टाइमर को एक शॉट में सेट करना चाहते हैं, या बाद में एक छोटे अंतराल पर दोहराना चाहते हैं। आप दोनों हाथों के लिए timer_settime() का उपयोग करते हैं, और टाइमर को निष्क्रिय करते हैं; विवरण के लिए man 2 timer_settime देखें।

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

अब, मूल प्रश्न दिलचस्प है, क्योंकि प्रभावी ढंग से उपयोग किए जाने पर टाइमर शक्तिशाली होते हैं। हालांकि, उदाहरण कार्यक्रम मूल रूप से बकवास है। आप ऐसा प्रोग्राम क्यों नहीं बनाते जो एक या अधिक टाइमर सेट करता है, उदाहरण के लिए प्रत्येक मानक आउटपुट में कुछ आउटपुट करता है? से write() एट अल का उपयोग करना याद रखें क्योंकि वे async-signal safe हैं, जबकि printf()stdio.h से et cetera नहीं हैं। (यदि आपके सिग्नल हैंडलर गैर-एसिंक-सिग्नल सुरक्षित फ़ंक्शंस का उपयोग करते हैं, तो परिणाम अनिर्धारित होते हैं। यह आमतौर पर काम करता है, लेकिन इसकी गारंटी नहीं है; यह काम के रूप में भी क्रैश हो सकता है। परीक्षण नहीं बताएगा, क्योंकि यह अपरिभाषित है ।)


जोड़ने के लिए संपादित: यहां मल्टीप्लेक्ड टाइमआउट का एक नंगे-हड्डियों का उदाहरण है।

(संभव सीमा कानून के तहत करने के लिए, मैं दुनिया भर में सार्वजनिक क्षेत्र के नीचे दिखाया गया कोड के टुकड़े करने के लिए सभी कॉपीराइट और संबंधित और पड़ोसी अधिकार समर्पित;। CC0 Public Domain Dedication देख दूसरे शब्दों में, किसी भी तरह से नीचे दिए गए कोड का उपयोग करने के लिए स्वतंत्र महसूस आप चाहते हैं, बस मुझे इसके साथ किसी भी समस्या के लिए दोष न दें।)

मैंने पुरानी शैली के जीसीसी परमाणु निर्मित इंस का उपयोग किया, इसलिए यह थ्रेड-सुरक्षित होना चाहिए। कुछ जोड़ों के साथ, इसे मल्टीथ्रेड कोड के लिए भी काम करना चाहिए। (आप, उदाहरण के mutexes के लिए उपयोग कर सकते हैं नहीं है, क्योंकि pthread_mutex_lock() नहीं async संकेत सुरक्षित है। Atomically टाइमआउट राज्यों से छेड़छाड़ काम करना चाहिए, हालांकि हो सकता है अगर आप एक समय समाप्ति बस जब यह आग को निष्क्रिय कुछ दौड़ छोड़ दिया है।)

#define _POSIX_C_SOURCE 200809L 
#include <unistd.h> 
#include <signal.h> 
#include <time.h> 
#include <errno.h> 

#define TIMEOUTS  16 
#define TIMEOUT_SIGNAL (SIGRTMIN+0) 

#define TIMEOUT_USED 1 
#define TIMEOUT_ARMED 2 
#define TIMEOUT_PASSED 4 

static timer_t    timeout_timer; 
static volatile sig_atomic_t timeout_state[TIMEOUTS] = { 0 }; 
static struct timespec  timeout_time[TIMEOUTS]; 


/* Return the number of seconds between before and after, (after - before). 
* This must be async-signal safe, so it cannot use difftime(). 
*/ 
static inline double timespec_diff(const struct timespec after, const struct timespec before) 
{ 
    return (double)(after.tv_sec - before.tv_sec) 
     + (double)(after.tv_nsec - before.tv_nsec)/1000000000.0; 
} 

/* Add positive seconds to a timespec, nothing if seconds is negative. 
* This must be async-signal safe. 
*/ 
static inline void timespec_add(struct timespec *const to, const double seconds) 
{ 
    if (to && seconds > 0.0) { 
     long s = (long)seconds; 
     long ns = (long)(0.5 + 1000000000.0 * (seconds - (double)s)); 

     /* Adjust for rounding errors. */ 
     if (ns < 0L) 
      ns = 0L; 
     else 
     if (ns > 999999999L) 
      ns = 999999999L; 

     to->tv_sec += (time_t)s; 
     to->tv_nsec += ns; 

     if (to->tv_nsec >= 1000000000L) { 
      to->tv_nsec -= 1000000000L; 
      to->tv_sec++; 
     } 
    } 
} 

/* Set the timespec to the specified number of seconds, or zero if negative seconds. 
*/ 
static inline void timespec_set(struct timespec *const to, const double seconds) 
{ 
    if (to) { 
     if (seconds > 0.0) { 
      const long s = (long)seconds; 
      long  ns = (long)(0.5 + 1000000000.0 * (seconds - (double)s)); 

      if (ns < 0L) 
       ns = 0L; 
      else 
      if (ns > 999999999L) 
       ns = 999999999L; 

      to->tv_sec = (time_t)s; 
      to->tv_nsec = ns; 

     } else { 
      to->tv_sec = (time_t)0; 
      to->tv_nsec = 0L; 
     } 
    } 
} 


/* Return nonzero if the timeout has occurred. 
*/ 
static inline int timeout_passed(const int timeout) 
{ 
    if (timeout >= 0 && timeout < TIMEOUTS) { 
     const int state = __sync_or_and_fetch(&timeout_state[timeout], 0); 

     /* Refers to an unused timeout? */ 
     if (!(state & TIMEOUT_USED)) 
      return -1; 

     /* Not armed? */ 
     if (!(state & TIMEOUT_ARMED)) 
      return -1; 

     /* Return 1 if timeout passed, 0 otherwise. */ 
     return (state & TIMEOUT_PASSED) ? 1 : 0; 

    } else { 
     /* Invalid timeout number. */ 
     return -1; 
    } 
} 

/* Release the timeout. 
* Returns 0 if the timeout had not fired yet, 1 if it had. 
*/ 
static inline int timeout_unset(const int timeout) 
{ 
    if (timeout >= 0 && timeout < TIMEOUTS) { 
     /* Obtain the current timeout state to 'state', 
     * then clear all but the TIMEOUT_PASSED flag 
     * for the specified timeout. 
     * Thanks to Bylos for catching this bug. */ 
     const int state = _sync_fetch_and_and(&timeout_state[timeout], TIMEOUT_PASSED); 

     /* Invalid timeout? */ 
     if (!(state & TIMEOUT_USED)) 
      return -1; 

     /* Not armed? */ 
     if (!(state & TIMEOUT_ARMED)) 
      return -1; 

     /* Return 1 if passed, 0 otherwise. */ 
     return (state & TIMEOUT_PASSED) ? 1 : 0; 

    } else { 
     /* Invalid timeout number. */ 
     return -1; 
    } 
} 


int timeout_set(const double seconds) 
{ 
    struct timespec now, then; 
    struct itimerspec when; 
    double   next; 
    int    timeout, i; 

    /* Timeout must be in the future. */ 
    if (seconds <= 0.0) 
     return -1; 

    /* Get current time, */ 
    if (clock_gettime(CLOCK_REALTIME, &now)) 
     return -1; 

    /* and calculate when the timeout should fire. */ 
    then = now; 
    timespec_add(&then, seconds); 

    /* Find an unused timeout. */ 
    for (timeout = 0; timeout < TIMEOUTS; timeout++) 
     if (!(__sync_fetch_and_or(&timeout_state[timeout], TIMEOUT_USED) & TIMEOUT_USED)) 
      break; 

    /* No unused timeouts? */ 
    if (timeout >= TIMEOUTS) 
     return -1; 

    /* Clear all but TIMEOUT_USED from the state, */ 
    __sync_and_and_fetch(&timeout_state[timeout], TIMEOUT_USED); 

    /* update the timeout details, */ 
    timeout_time[timeout] = then; 

    /* and mark the timeout armable. */ 
    __sync_or_and_fetch(&timeout_state[timeout], TIMEOUT_ARMED); 

    /* How long till the next timeout? */ 
    next = seconds; 
    for (i = 0; i < TIMEOUTS; i++) 
     if ((__sync_fetch_and_or(&timeout_state[i], 0) & (TIMEOUT_USED | TIMEOUT_ARMED | TIMEOUT_PASSED)) == (TIMEOUT_USED | TIMEOUT_ARMED)) { 
      const double secs = timespec_diff(timeout_time[i], now); 
      if (secs >= 0.0 && secs < next) 
       next = secs; 
     } 

    /* Calculate duration when to fire the timeout next, */ 
    timespec_set(&when.it_value, next); 
    when.it_interval.tv_sec = 0; 
    when.it_interval.tv_nsec = 0L; 

    /* and arm the timer. */ 
    if (timer_settime(timeout_timer, 0, &when, NULL)) { 
     /* Failed. */ 
     __sync_and_and_fetch(&timeout_state[timeout], 0); 
     return -1; 
    } 

    /* Return the timeout number. */ 
    return timeout; 
} 


static void timeout_signal_handler(int signum __attribute__((unused)), siginfo_t *info, void *context __attribute__((unused))) 
{ 
    struct timespec now; 
    struct itimerspec when; 
    int    saved_errno, i; 
    double   next; 

    /* Not a timer signal? */ 
    if (!info || info->si_code != SI_TIMER) 
     return; 

    /* Save errno; some of the functions used may modify errno. */ 
    saved_errno = errno; 

    if (clock_gettime(CLOCK_REALTIME, &now)) { 
     errno = saved_errno; 
     return; 
    } 

    /* Assume no next timeout. */ 
    next = -1.0; 

    /* Check all timeouts that are used and armed, but not passed yet. */ 
    for (i = 0; i < TIMEOUTS; i++) 
     if ((__sync_or_and_fetch(&timeout_state[i], 0) & (TIMEOUT_USED | TIMEOUT_ARMED | TIMEOUT_PASSED)) == (TIMEOUT_USED | TIMEOUT_ARMED)) { 
      const double seconds = timespec_diff(timeout_time[i], now); 
      if (seconds <= 0.0) { 
       /* timeout [i] fires! */ 
       __sync_or_and_fetch(&timeout_state[i], TIMEOUT_PASSED); 

      } else 
      if (next <= 0.0 || seconds < next) { 
       /* This is the soonest timeout in the future. */ 
       next = seconds; 
      } 
     } 

    /* Note: timespec_set() will set the time to zero if next <= 0.0, 
    *  which in turn will disarm the timer. 
    * The timer is one-shot; it_interval == 0. 
    */ 
    timespec_set(&when.it_value, next); 
    when.it_interval.tv_sec = 0; 
    when.it_interval.tv_nsec = 0L; 
    timer_settime(timeout_timer, 0, &when, NULL); 

    /* Restore errno. */ 
    errno = saved_errno; 
} 


int timeout_init(void) 
{ 
    struct sigaction act; 
    struct sigevent evt; 
    struct itimerspec arm; 

    /* Install timeout_signal_handler. */ 
    sigemptyset(&act.sa_mask); 
    act.sa_sigaction = timeout_signal_handler; 
    act.sa_flags = SA_SIGINFO; 
    if (sigaction(TIMEOUT_SIGNAL, &act, NULL)) 
     return errno; 

    /* Create a timer that will signal to timeout_signal_handler. */ 
    evt.sigev_notify = SIGEV_SIGNAL; 
    evt.sigev_signo = TIMEOUT_SIGNAL; 
    evt.sigev_value.sival_ptr = NULL; 
    if (timer_create(CLOCK_REALTIME, &evt, &timeout_timer)) 
     return errno; 

    /* Disarm the timeout timer (for now). */ 
    arm.it_value.tv_sec = 0; 
    arm.it_value.tv_nsec = 0L; 
    arm.it_interval.tv_sec = 0; 
    arm.it_interval.tv_nsec = 0L; 
    if (timer_settime(timeout_timer, 0, &arm, NULL)) 
     return errno; 

    return 0; 
} 

int timeout_done(void) 
{ 
    struct sigaction act; 
    struct itimerspec arm; 
    int    errors = 0; 

    /* Ignore the timeout signals. */ 
    sigemptyset(&act.sa_mask); 
    act.sa_handler = SIG_IGN; 
    if (sigaction(TIMEOUT_SIGNAL, &act, NULL)) 
     if (!errors) errors = errno; 

    /* Disarm any current timeouts. */ 
    arm.it_value.tv_sec = 0; 
    arm.it_value.tv_nsec = 0L; 
    arm.it_interval.tv_sec = 0; 
    arm.it_interval.tv_nsec = 0; 
    if (timer_settime(timeout_timer, 0, &arm, NULL)) 
     if (!errors) errors = errno; 

    /* Destroy the timer itself. */ 
    if (timer_delete(timeout_timer)) 
     if (!errors) errors = errno; 

    /* If any errors occurred, set errno. */ 
    if (errors) 
     errno = errors; 

    /* Return 0 if success, errno otherwise. */ 
    return errors; 
} 

संकलन करते समय rt लाइब्रेरी को शामिल करना याद रखें, यानी संकलन के लिए gcc -W -Wall *source*.c -lrt -o *binary* का उपयोग करें।

विचार यह है कि मुख्य कार्यक्रम पहले timeout_init() कॉल के लिए सभी आवश्यक संचालकों वगैरह स्थापित करने के लिए, और (fork() के बाद या एक बच्चे की प्रक्रिया में ing) बाहर निकलने से पहले यह deistall को timeout_done() कह सकते है।

टाइमआउट सेट करने के लिए, आप timeout_set(seconds) पर कॉल करें। वापसी मूल्य एक टाइमआउट वर्णनकर्ता है। वर्तमान में केवल एक ध्वज है जिसे आप timeout_passed() का उपयोग करके जांच सकते हैं, लेकिन टाइमआउट सिग्नल की डिलीवरी किसी भी ब्लॉकिंग I/O कॉल को बाधित करती है। इस प्रकार, आप किसी भी अवरुद्ध I/O कॉल को बाधित करने के लिए टाइमआउट की अपेक्षा कर सकते हैं।

यदि आप टाइमआउट पर ध्वज सेट करने से कुछ और करना चाहते हैं, तो आप इसे सिग्नल हैंडलर में नहीं कर सकते हैं; याद रखें, सिग्नल हैंडलर में, आप एसिंक-सिग्नल सुरक्षित कार्यों तक ही सीमित हैं। sigwaitinfo() पर एक अंतहीन लूप के साथ एक अलग थ्रेड का उपयोग करना है, TIMEOUT_SIGNAL सिग्नल सभी अन्य धागे में अवरुद्ध है। इस तरह समर्पित थ्रेड को सिग्नल पकड़ने की गारंटी है, लेकिन साथ ही, एसिंक-सिग्नल सुरक्षित कार्यों तक ही सीमित नहीं है। उदाहरण के लिए, यह अधिक काम कर सकता है, या pthread_kill() का उपयोग करके एक विशिष्ट थ्रेड को सिग्नल भी भेज सकता है। (जब तक उस सिग्नल में एक हैंडलर होता है, यहां तक ​​कि एक खाली शरीर के साथ भी, इसकी डिलीवरी उस थ्रेड में किसी भी अवरुद्ध I/O कॉल को बाधित करेगी।)

टाइमआउट का उपयोग करने के लिए main() एक साधारण उदाहरण है। यह मूर्खतापूर्ण है, और fgets() पर पुनः प्रयास नहीं करता है (जब सिग्नल द्वारा बाधित होता है), लेकिन ऐसा लगता है कि यह काम करता है।

#include <string.h> 
#include <stdio.h> 

int main(void) 
{ 
    char buffer[1024], *line; 
    int t1, t2, warned1; 

    if (timeout_init()) { 
     fprintf(stderr, "timeout_init(): %s.\n", strerror(errno)); 
     return 1; 
    } 

    printf("You have five seconds to type something.\n"); 
    t1 = timeout_set(2.5); warned1 = 0; 
    t2 = timeout_set(5.0); 
    line = NULL; 

    while (1) { 

     if (timeout_passed(t1)) { 
      /* Print only the first time we notice. */ 
      if (!warned1++) 
       printf("\nTwo and a half seconds left, buddy.\n"); 
     } 

     if (timeout_passed(t2)) { 
      printf("\nAw, just forget it, then.\n"); 
      break; 
     } 

     line = fgets(buffer, sizeof buffer, stdin); 
     if (line) { 
      printf("\nOk, you typed: %s\n", line); 
      break; 
     } 
    } 

    /* The two timeouts are no longer needed. */ 
    timeout_unset(t1); 
    timeout_unset(t2); 

    /* Note: 'line' is non-NULL if the user did type a line. */ 

    if (timeout_done()) { 
     fprintf(stderr, "timeout_done(): %s.\n", strerror(errno)); 
     return 1; 
    } 

    return 0; 
} 
+1

@ बाइलोस: 'timeout_unset()' में बग को ध्यान में रखने के लिए धन्यवाद। 'राज्य' ध्वज और टाइमआउट टाइमर राज्य परिवर्तन के इरादे का वर्णन करने वाली टिप्पणी वास्तव में खराब थी, इसलिए मैंने इसे भी ठीक किया। –

2

एक उपयोगी पढ़ने time(7) आदमी पृष्ठ है। ध्यान दें कि लिनक्स भी timerfd_create(2) लिनक्स विशिष्ट syscall प्रदान करता है, बार (या या ppoll(2) बड़े select(2) syscall) poll(2) की तरह एक बहुसंकेतन syscall के साथ प्रयोग किया।

आप संकेतों का उपयोग करने के लिए मत भूलना ध्यान से signal(7) आदमी पेज में पढ़ना चाहते हैं (वहाँ संकेत संचालकों कोडिंग के बारे में प्रतिबंध हैं, आप अपने संकेत संचालकों में एक volatile sigatomic_t चर सेट करना चाहें, आपको नहीं करना चाहिए किसी भी new या delete -या malloc & free - सिग्नल हैंडलर के अंदर मेमोरी मेनगेनमेंट ऑपरेशंस, जहां केवल async-safe फ़ंक्शन कॉल की अनुमति है।)।

ध्यान दें कि घटना-उन्मुख प्रोग्रामिंग, जैसे कि जीयूआई अनुप्रयोग, अक्सर libevent के साथ, क्यूटी में जीटीके में, ....) उनके ईवेंट लूप में टाइमर प्रबंधित करने के लिए।