سؤال

في البرمجة المدمجة التقليدية، سنعطي دالة تأخير كما يلي:

for(i=0;i<255;i++)
   for(j=0;j<255;j++);

من وجهة نظر المعالج الدقيق، هل هذه هي الطريقة التي تعمل بها وظيفة النوم ()؟

هل هناك بديل لوظيفة النوم () في لغة C؟

هل كانت مفيدة؟

المحلول

وبدائل تعتمد في ما تحاول القيام به وما OS كنت على.

إذا كنت ترغب فقط لإضاعة الوقت، فإن هذه قد تساعد:

في معظم أنظمة يونكس من نوع ستجد وظيفة "usleep"، التي هي أكثر أو أقل مثل النوم مع أكبر القرار. كن حذرا مع هذا واحد لأنه عادة لا يستطيع النوم لميكروثانية واحدة فقط.

في بعض أنظمة يونكس من نوع، واستدعاء نظام مختارة يمكن استخدامها مع جميع مجموعات ملف اصف الصفر من أجل الحصول على دقيقة إلى حد ما الانتظار الفرعي الثاني.

في أنظمة ويندوز، لديك النوم، والذي هو الى حد كبير نفس، ولكن اتخاذ عدد من ميلي ثانية.

في نظام التشغيل متعددة المهام، وهي وظيفة النوم يمكن في بعض الأحيان أن تعطى 0 كمعلمة. هذا يسبب عموما وظيفة للتخلي انها timeslice، ولكن يمكن إعادة جدولتها على الفور إذا ليست مهمة أخرى جاهزة للتشغيل.

نصائح أخرى

ويسمى هذا النوع من حلقة التي تصف "الانتظار مشغول". في أنظمة التشغيل الحقيقية، النوم لا يسبب الانتظار مشغول. ويحكي نظام التشغيل لعدم جدولة عملية في حتى فترة النوم قد انتهت.

واحد آلية مشتركة هو استخدام select() هو أن يضمن أن المهلة، وتحديد وقت النوم كما المهلة:

// Sleep for 1.5 sec
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 500000;
select(0, NULL, NULL, NULL, &tv);

وعادة ما يستخدم select() للتحقق مجموعة من واصفات الملفات وانتظر حتى واحد على الأقل على استعداد لأداء I / O. إذا ليس هناك ما هو على استعداد (أو، في هذه الحالة، إذا لم يتم تحديد قوات الدفاع والأمن)، وسوف مهلة.

وميزة select() خلال حلقة مشغول هو أنه يستهلك موارد قليلة جدا أثناء النوم، بينما حلقة مشغول تحتكر المعالج بقدر ما يسمح به مستوى أولوياتها.

هل عدم استخدام الشفرة التي نشرت على النوم على نظام مضمن. ومن شأن مترجم لائق حذفها تماما، وحتى إذا لم المترجم الخاص بك إزالته هو الأمثل، لأن تشغيل المعالج في حلقة ضيقة سوف يحرق طاقة، وهي مسألة لنظام مضمن. حتى الأنظمة التي لا تعمل على رعاية البطارية حول استخدام القوة، منذ أقل استهلاك الطاقة يعني أرخص مصادر الطاقة والتبريد.

والطريقة التي تفعل عادة هذه هي وحدة المعالجة المركزية الخاصة بك تنفيذ نوعا من IDLE أو SLEEP التعليمات، التي من شأنها أن تتسبب في توقف مؤقتا معالجة الأوامر. وعلى خط المقاطعة خارجي متصل دائرة الموقت يستيقظ المعالج احتياطية على فترات منتظمة، والتي تشير الاختبارات وحدة المعالجة المركزية لمعرفة ما إذا كان نائما لفترة طويلة بما فيه الكفاية، وإذا لم يكن ذلك يعود الى النوم.

//Pseudo code
int start = getTime();
int end = start + sleepTime;

while (getTime() < end) {
       asm("SLEEP");
}

والتفاصيل الدقيقة تختلف من معالج إلى معالج. إذا كنت تقوم بتشغيل كعملية على OS الدعوة النوم عموما مجرد يحكي جدولة لوقف عملية الخاص بك، ومن ثم يقرر ما إذا كان نواة لجدولة عملية أخرى أو للنوم وحدة المعالجة المركزية. أيضا، فإن رمز أعلاه لا تكون adequete لأنظمة الوقت الحقيقي، والتي تريد ضمانات الموعد النهائي، وما إلى ذلك وفي تلك الحالات سوف تحتاج إلى الحصول على الوقت في الحلقة، ومعرفة مدة من الوقت يقطع ذلك أوو معرفة ما إذا كان يمكنك resleep دون تهب الموعد المحدد، وربما إعادة برمجة أجهزة توقيت أو الانتظار مشغول.

وأنت تتحدث عن "البرمجة جزءا لا يتجزأ من" في OP. إذا كنت تقوم بعمل جزءا لا يتجزأ من وبحاجة الى شيء مثل النوم ()، غالبا ما تكون هناك عدادات الأجهزة / توقيت المتاحة. وهذا يختلف من الهندسة المعمارية والعمارة وحتى يكون لها نظرة على ورقة البيانات.

إذا كنت لا تفعل العمل جزءا لا يتجزأ، أعتذر:)

إذا كنت تستخدم حلقات for، فمن الأفضل أن تعرف ما الذي يتم تجميعه إليه والمدة التي تستغرقها هذه التعليمات بسرعة الساعة المحددة لديك، و تأكد من أن وحدة المعالجة المركزية تقوم بتشغيل تعليماتك ولا شيء آخر (يمكن القيام بذلك في الأنظمة المضمنة ولكنه أمر صعب لأنه لا يسمح بالمقاطعات).

وإلا فلن تكون قادرًا على معرفة المدة التي سيستغرقها الأمر حقًا.

واجهت ألعاب الكمبيوتر الشخصي المبكرة هذه المشكلة - فقد تم تصميمها لجهاز كمبيوتر يعمل بسرعة 4.7 ميجاهرتز، وعندما ظهرت أجهزة الكمبيوتر الأسرع، أصبحت غير قابلة للعب.

أفضل طريقة يمكن أن يعمل بها "النوم" هي أن تعرف وحدة المعالجة المركزية الوقت في أي وقت.ليس بالضرورة الوقت الفعلي (7:15 صباحًا) ولكن على الأقل الوقت النسبي (8612 ثانية منذ وقت ما).

وبهذه الطريقة يمكن تطبيق دلتا على الوقت الحالي والانتظار في حلقة حتى يتم الوصول إلى دلتا + الحالية.

أي شيء يعتمد على عدد دورات وحدة المعالجة المركزية لا يمكن الاعتماد عليه بطبيعته لأن وحدة المعالجة المركزية قد تنتقل إلى مهمة أخرى وتترك حلقتك معلقة.

لنفترض أن لديك منفذ إدخال/إخراج 16 بت معين للذاكرة والذي تزيد وحدة المعالجة المركزية منه مرة واحدة في الثانية.لنفترض أيضًا أنه موجود في موقع الذاكرة 0x33 في نظامك المضمن، حيث يبلغ عدد ints أيضًا 16 بت.تصبح الوظيفة التي تسمى النوم شيئًا مثل:

void sleep (unsigned int delay) {
    unsigned int target = peek(0x33) + delay;
    while (peek(0x33) != target);
}

سيتعين عليك التأكد من أن peek() تقوم بإرجاع محتويات الذاكرة في كل مرة (بحيث لا يؤدي تحسين المترجمين إلى إفساد المنطق) وأن عبارة while الخاصة بك تعمل أكثر من مرة في الثانية حتى لا تفوت الهدف، ولكن هذه هي قضايا تشغيلية لا تؤثر على المفهوم الذي أعرضه.

هناك المزيد من المعلومات حول كيفية عمل Sleep() هنا

بالمناسبة، الانتظار المزدحم ليس بالضرورة مخصصًا للهواة - على الرغم من أنه يحرق المعالج الذي قد ترغب في استخدامه لغرض آخر.إذا كنت تستخدم مصدرًا زمنيًا، فأنت مقيد بتفاصيل هذا المصدر.على سبيل المثال.إذا كان لديك مؤقت 1 مللي ثانية، وتريد الحصول على 500 وحدة، فلديك مشكلة.إذا كان نظامك المضمن قادرًا على التعامل مع حقيقة أنك ستصدر صوتًا في حلقة لمدة 500 ثانية، فقد يكون ذلك مقبولاً.وحتى إذا كان لديك مؤقت بالتفاصيل التي تريدها، فأنت بحاجة أيضًا إلى مقاطعة ذلك المؤقت في الوقت المناسب... ثم إرسال معالج المقاطعة... ثم الوصول إلى الكود الخاص بك.في بعض الأحيان تكون الحلقة المزدحمة هي الحل الأكثر ملاءمة. أحيانا.

ومشغول-الانتظار هو للهواة حتى في نظام مضمن، استخدام مصدر في الوقت الحقيقي.

ان اي C مترجم لائق، دون العمل الإضافي، وإزالة الشفرة تماما وان تأخير تتلاشى

والنوم واجهات فعلا مع نظام التشغيل، حيث يتم وضع العمليات النوم خارج قائمة الانتظار الجدولة. وعادة ما تستخدم:

poll(0, 0, milliseconds);

ولأنظمة متوافقة مع POSIX. يعمل select أيضا للنوافذ (يجب أن لديهم API الأصلي (ربما يسمى Sleep) لذلك).

والصفحة 20 في "خيوط في C #" من قبل جوسيف البهاري لها مناقشة مثيرة للاهتمام من هذا. لا يمكنك النوم لأقل من 1 مللي ثانية في صافي لكن DateTime.Ticks ديه تحبب من 100 نانو ثانية (= 0.1 ميكروثانية) فترات. للسيطرة على بلدي 5 محور CNC السائر أنا فقط بحاجة إلى وقفة لمدة 10 ميكروثانية بين الأوامر خطوة. ولقد استخدمت وحدة تحكم الجزئي للقيام حلقات سيئة ولكن اعتقد انه على ما يرام تسليم معالج لهذا المنصب إذا كان لديك مجموعة كاملة على أي حال، والتوقف عن موضوع عندما تستطيع. على الأقل لن يكون دائما نفس واحدة.

#include <Windows.h>

static NTSTATUS(__stdcall *NtDelayExecution)(BOOL Alertable, PLARGE_INTEGER DelayInterval) = (NTSTATUS(__stdcall*)(BOOL, PLARGE_INTEGER)) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtDelayExecution");

static NTSTATUS(__stdcall *ZwSetTimerResolution)(IN ULONG RequestedResolution, IN BOOLEAN Set, OUT PULONG ActualResolution) = (NTSTATUS(__stdcall*)(ULONG, BOOLEAN, PULONG)) GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwSetTimerResolution");




static void SleepShort(float milliseconds) {
    static bool once = true;
    if (once) {
        ULONG actualResolution;
        ZwSetTimerResolution(1, true, &actualResolution);
        once = false;
    }

    LARGE_INTEGER interval;
    interval.QuadPart = -1 * (int)(milliseconds * 10000.0f);
    NtDelayExecution(false, &interval);
}

ونعم أنه يستخدم بعض الوظائف نواة غير الموثقة، ولكن بصراحة، فإنه أسرع بكثير من معظم الاقتراحات ويعمل بشكل جيد جدا، (لاحظ أنه سيقتصر على مبلغ وحدة المعالجة المركزية، على سبيل المثال الألغام أستطيع النوم فقط 500 نانو ثانية (0.5))

والمتوفرة في لينكس usleep (ميكرو دولية) nanosleep (...) أكثر دقة رؤية رجل صفحات لاستدعاء الحجج

في نظام التشغيل يونكس المشتقة، وكنت ربما جدولة مكالمة إشارة ()، وسوف الشفرة ببساطة كتلة التعليمات البرمجية حتى يتم رفع إشارة. وتهدف إشارات لهذا الغرض، وأنها بسيطة جدا وفعالة.

ومحاولة ... لحل هذه المسألة حقا، أي شيء يعمل (وليس مثل محاولات أعلاه من الإجابة) لول

وأنا لا تزال لديها لتحسين هذا الرمز لجعله خارج. قليل من الإضافات هي موضع ترحيب.

// Sleep for both Windows and Linux: 
// Too bad? No one proposed you a solution that works? 
// Since Windows has no select.h nor poll.h, an implementation
// is necessary.
//  
// Solutions on boards are often refered to use either select or poll, but ok, what about C (not c++)?
//
/// implementation of poll is destined in this attempt for windows
/// Ideally, you add this part of code to the header of you *.c file, and it might work through...

#ifdef WIN32
#include <time.h>
#include <sys/time.h>
#include <ws2tcpip.h>
#include <Winsock2.h>
#include <windows.h>
/* winsock doesn't feature poll(), so there is a version implemented
 * in terms of select() in mingw.c. The following definitions
 * are copied from linux man pages. A poll() macro is defined to
 * call the version in mingw.c.
 */
#define POLLIN      0x0001    /* There is data to read */
#define POLLPRI     0x0002    /* There is urgent data to read */
#define POLLOUT     0x0004    /* Writing now will not block */
#define POLLERR     0x0008    /* Error condition */
#define POLLHUP     0x0010    /* Hung up */
#define POLLNVAL    0x0020    /* Invalid request: fd not open */
struct pollfd {
  SOCKET fd;        /* file descriptor */
  short events;     /* requested events */
  short revents;    /* returned events */
};

int mingw_poll (struct pollfd *, unsigned int, int);

#define poll(x, y, z)        mingw_poll(x, y, z)
#endif





int mingw_poll(struct pollfd *fds, unsigned int nfds, int timo)
{
    struct timeval timeout, *toptr;
    fd_set ifds, ofds, efds, *ip, *op;
    int i, rc;

    /* Set up the file-descriptor sets in ifds, ofds and efds. */
    FD_ZERO(&ifds);
    FD_ZERO(&ofds);
    FD_ZERO(&efds);
    for (i = 0, op = ip = 0; i < nfds; ++i) {
    fds[i].revents = 0;
    if(fds[i].events & (POLLIN|POLLPRI)) {
        ip = &ifds;
        FD_SET(fds[i].fd, ip);
    }
    if(fds[i].events & POLLOUT) {
        op = &ofds;
        FD_SET(fds[i].fd, op);
    }
    FD_SET(fds[i].fd, &efds);
    } 

    /* Set up the timeval structure for the timeout parameter */
    if(timo < 0) {
    toptr = 0;
    } else {
    toptr = &timeout;
    timeout.tv_sec = timo / 1000;
    timeout.tv_usec = (timo - timeout.tv_sec * 1000) * 1000;
    }

#ifdef DEBUG_POLL
    printf("Entering select() sec=%ld usec=%ld ip=%lx op=%lx\n",
           (long)timeout.tv_sec, (long)timeout.tv_usec, (long)ip, (long)op);
#endif
    rc = select(0, ip, op, &efds, toptr);
#ifdef DEBUG_POLL
    printf("Exiting select rc=%d\n", rc);
#endif

    if(rc <= 0)
    return rc;

    if(rc > 0) {
        for (i = 0; i < nfds; ++i) {
            int fd = fds[i].fd;
        if(fds[i].events & (POLLIN|POLLPRI) && FD_ISSET(fd, &ifds))
            fds[i].revents |= POLLIN;
        if(fds[i].events & POLLOUT && FD_ISSET(fd, &ofds))
            fds[i].revents |= POLLOUT;
        if(FD_ISSET(fd, &efds))
            /* Some error was detected ... should be some way to know. */
            fds[i].revents |= POLLHUP;
#ifdef DEBUG_POLL
        printf("%d %d %d revent = %x\n", 
                FD_ISSET(fd, &ifds), FD_ISSET(fd, &ofds), FD_ISSET(fd, &efds), 
                fds[i].revents
        );
#endif
        }
    }
    return rc;
}

ولقد وجدت وظيفة في هذا المنصب ( HTTP: //cboard.cprogramming.com/c-programming/111229-how-use-sleep-function.html ) ويعمل:

#include <stdio.h>
#include <windows.h>

int main()
{
    puts("Hello \n");
    /* in windows.h is declared the Sleep (upper S) function and it takes time in 
miliseconds */
    Sleep(3000);
    puts("World \n");
    return 0;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top