2015-08-22 21 views
9

मैंने TomTom GPS watches over Bluetooth से बात करने के लिए एक उपयोगिता लिखी है, और इसे रन-एंड-भूल पृष्ठभूमि डिमन के रूप में अच्छी तरह से चलाने की कोशिश कर रहा हूं।रीयल-टाइम जागरूक नींद() कॉल?

कार्यक्रम समय-समय पर जीपीएस डिवाइस के साथ संचार करता है और फिर sleep एस थोड़ी देर तक इसकी आवश्यकता होती है।

मैंने देखा है कि sleep() सिस्टम निलंबन के साथ अजीब तरीके से इंटरैक्ट करता है: जब मैं सिस्टम निलंबन (लैपटॉप चल रहा है लिनक्स 3.16.0 कर्नेल) दर्ज करता हूं और फिर कंप्यूटर को बैक अप लेता हूं, sleep निलंबन समय को नोटिस नहीं करता है। उदाहरण के लिए, ले निम्नलिखित sleep.c:

#include <time.h> 
#include <stdio.h> 
#include <unistd.h> 

int main(int argc, char**argv) 
{ 
    time_t t=time(NULL); 
    printf("sleep at: %s", ctime(&t)); 

    sleep(atoi(argv[1])); 

    t=time(NULL); 
    printf("wake at: %s", ctime(&t)); 
} 
[email protected]:~$ 

संकलित, चलाने के लिए, और आधे रास्ते के माध्यम से सो;

$ gcc sleep.c -o sleep 
$ ./sleep 30 
sleep at: Fri Aug 21 21:05:36 2015 
<suspend computer for 17 seconds> 
wake at: Fri Aug 21 21:06:23 2015 

वहाँ एक रास्ता घड़ी के समय बजाय प्रणाली सक्रिय रहने की अवधि -aware -aware है कि में प्रोग्राम निष्पादन को निलंबित करने का एक सही तरीका है?

(मैं भी usleep की कोशिश की है, nanosleep, और alarm और पाया है कि वे इसी तरह व्यवहार करते हैं।)

अद्यतन:setitimer, के रूप में @HuStmpHrrr ने सुझाव दिया, काफी होनहार लग रहा था ... लेकिन प्रतीत होता है एक ही समस्या है।

इस संस्करण का अनुरोध किया 30 से अधिक के लिए रुक जाता है जब मैं इसे के बीच में निलंबित ...

#include <time.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <signal.h> 
#include <sys/time.h> 

void sighandler() {} 

int main(int argc, char**argv) 
{ 
    time_t t=time(NULL); 
    printf("sleep at: %s", ctime(&t)); 

    signal(SIGALRM, sighandler); 
    struct itimerval timer = {.it_interval={0,0}, 
           .it_value={atoi(argv[1]),0}}; 
    setitimer(ITIMER_REAL, &timer, NULL); 
    pause(); 

    t=time(NULL); 
    printf("wake at: %s", ctime(&t)); 
} 
+0

किस बारे में 'alarm'? 'अलार्म() सेकेंड सेकेंड में कॉलिंग प्रक्रिया में एक SIGALRM सिग्नल को वितरित करने की व्यवस्था करता है।' वादा करता है। – HuStmpHrrr

+1

'setitimer' अधिक नियंत्रण प्रदान करता है। आप जो चाहते हैं उसे प्राप्त करने के लिए आप 'ITIMER_REAL' में जा सकते हैं। – HuStmpHrrr

+0

'setitimer' बहुत ही आशाजनक लग रहा था लेकिन ऐसा लगता है कि इसमें "डाउनटाइम" नहीं है। मतदान 'समय' काफी असाधारण समाधान की तरह लगता है लेकिन संभवतः सही :( –

उत्तर

5

कुछ समाधान और संभावित समाधानों: एक पाश में

नींद और वास्तविक जाँच बीता हुआ समय

वहाँ लगभग निश्चित रूप से यह या होना चाहिए करने के लिए एक बेहतर तरीका है -लेकिन यहाँ समय से किया जा रहा के लिए अपने आवेदन के लिए एक स्वीकार्य समाधान है:

  • जब एक लंबे अंतराल (> 30) के लिए सोने के लिए की आवश्यकता होगी,, मैं sleep(30) बार-बार करते हैं, यह जांच करना कि असली बीता हुआ समय (time(NULL)-start_time) कुल इच्छित विराम से अधिक समय नहीं है।

  • इस तरह, यदि सिस्टम को निलंबित कर दिया गया है, तो 3 घंटे, वांछित प्रोग्राम रोक 1 घंटे है, निलंबन के कारण अतिरिक्त देरी 30 सेकंड से अधिक नहीं होगी। यह करने के लिए

कोड:

void nullhandler(int signal) {} 

int isleep(int seconds, int verbose) 
{ 
    if (verbose) { 
     fprintf(stderr, "Sleeping for %d seconds...", seconds); 
     fflush(stderr); 
    } 
    signal(SIGALRM, nullhandler); 

    // weird workaround for non-realtime-awareness of sleep: 
    // https://stackoverflow.com/questions/32152276/real-time-aware-sleep-call 
    int res=0, elapsed=0; 
    for (time_t t=time(NULL); (elapsed<seconds) && (res<=0); elapsed=time(NULL)-t) 
     res = sleep((seconds-elapsed > 30) ? 30 : seconds-elapsed); 

    signal(SIGALRM, SIG_IGN); 
    if (res && verbose) 
     fprintf(stderr, "%s\n\n", res ? " woken by signal!" : ""); 
    return (res>0); 
} 

वेकअप कॉलबैक

@Speed8ump प्रणाली Wakeup सूचनाओं के लिए एक कॉलबैक दर्ज की सलाह दी। This thread over at AskUbuntu दिखाता है कि यह कैसे करें। एक अच्छा समाधान, लेकिन अब मैं अपने अपेक्षाकृत निम्न-स्तर कोड को एक विशेष डेस्कटॉप वातावरण के लिए दृढ़ता से बांधने से बचना चाहता हूं।

timer_settime

यह मेरी राय में सबसे सुंदर और सही समाधान है, और @NominalAnimal द्वारा सुझाव दिया गया था। यह time_settime() और librt से दोस्तों का उपयोग करता है।

ध्यान दें कि आदेश को निलंबित प्रणाली के साथ सही ढंग से इस काम बनाने के लिए, आप TIMER_ABSTIME साथ CLOCK_REALTIME का उपयोग करना चाहिए, प्रति timer_settime प्रलेखन:

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

यहाँ एक डेमो (librt साथ लिंक gcc -lrt -o sleep sleep.c, उदा) है:

#include <time.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <signal.h> 
#include <sys/time.h> 
#include <string.h> 
#include <stdlib.h> 

void sighandler(int signal) {} 

void isleep(int seconds) 
{ 
    timer_t timerid; 
    struct sigevent sev = { .sigev_notify=SIGEV_SIGNAL, 
          .sigev_signo=SIGALRM, 
          .sigev_value=(union sigval){ .sival_ptr = &timerid } }; 
    signal(SIGALRM, sighandler); 
    timer_create(CLOCK_REALTIME, &sev, &timerid); 

    struct itimerspec its = {.it_interval={0,0}}; 
    clock_gettime(CLOCK_REALTIME, &its.it_value); 
    its.it_value.tv_sec += seconds; 
    timer_settime(timerid, TIMER_ABSTIME, &its, NULL); 
    pause(); 
    signal(SIGALRM, SIG_IGN); 
} 

int main(int argc, char**argv) 
{ 
    time_t t=time(NULL); 
    printf("sleep at: %s", ctime(&t)); 

    isleep(atoi(argv[1])); 

    t=time(NULL); 
    printf("wake at: %s", ctime(&t)); 
} 
संबंधित मुद्दे