Когда и зачем нужен сон ()? - PullRequest
2 голосов
/ 18 марта 2009
cout<<"abcd";

sleep(100);

cout<<'\b';

Если я хочу напечатать строку, а затем вернуть один символ, зачем нужен сон () здесь?

Но при использовании printf в C кажется, что в этом нет необходимости, почему?

char* a = "12345";
char* b = "67890";
threadA(){cout<<a;}
threadB(){cout<<b;}

beginthread (threadA);
sleep(100);
beginthread (threadB);

Во втором приведенном выше псевдокоде правильно ли использовать sleep ()?

Ответы [ 12 ]

25 голосов
/ 18 марта 2009

Для расчета даты завтрашнего дня:

void get_tomorrow_date( struct timeval *date )
{
    sleep( 86400 ); // 60 * 60 * 24
    gettimeofday( date, 0 );
}

;)

9 голосов
/ 18 марта 2009

Есть две тонкие проблемы, которые вам нужно понять:

  • Многопоточность
  • Ввод / вывод и буферизация

Я постараюсь дать вам некоторое представление:

Многопоточность и сон

Имеет смысл sleep в многопоточной среде. Вызов sleep заставляет вас ждать, предоставляя начальному потоку некоторую область, чтобы завершить его обработку, то есть записывать строку abcd в стандартный вывод, прежде чем другой поток вставит символ возврата. Если бы вы не ожидали, пока первый поток завершит свою обработку, вы сначала написали бы символ возврата, а затем строку abcd и не заметили бы никакой разницы.

Буферизованный ввод / вывод

Ввод / вывод обычно происходит в буферизованном, небуферизованном и полубуферизованном состояниях. Это может повлиять на то, как долго, если вообще нужно, ждать, пока вывод появится на консоли.

Возможно, ваша реализация cout использует буферизованную модель. Попробуйте добавить новую строку или endl в конце ваших cout операторов, чтобы напечатать новую строку и сразу же сбросить ее, или используйте cout << "abcd" << flush; для сброса без печати новой строки.

5 голосов
/ 18 марта 2009

Во втором случае без сна есть тонкий шанс, что второй поток может начать работать раньше первого, что приведет к выводу "6789012345".

Однако «сон» на самом деле не способ обработки синхронизации между потоками. Обычно вы используете семафор или подобное в threadA(), который threadB() должен подождать, прежде чем выполнять свою работу.

2 голосов
/ 18 марта 2009

Я думаю, вам нужно понять, что вообще делает sleep, и понять, почему оно может существовать.

sleep делает то, на что это похоже. Он инструктирует ОС перевести запрашивающую задачу (где задача является потоком выполнения) в спящий режим, удалив ее из списка запущенных в данный момент процессов и поместив в какую-то очередь ожидания.

Обратите внимание, что бывают случаи, когда ОС усыпляет вас, нравится вам это или нет. Примером может служить любая форма блокировки ввода / вывода, например, чтение файла с диска. ОС делает это так, что другие задачи могут привлечь внимание процессора, пока вы не ждете ваших данных.

Можно использовать sleep добровольно для тех же целей, что и ОС. Например, если у вас есть несколько потоков, и они ожидают завершения какого-либо вычисления, вы, вероятно, захотите добровольно отказаться от ЦП, чтобы вычисления могли завершиться. Вы также можете добровольно отказаться от процессора, чтобы другие потоки имели возможность работать. Например, если у вас узкий цикл, сильно нагруженный процессором, вам нужно sleep время от времени, чтобы другие потоки могли работать.

То, что вы делаете, похоже, спит ради того, чтобы что-то было сброшено на стандартный вывод, чтобы какой-то другой поток не записывал на стандартный вывод перед вами. Это, однако, не гарантированно сработает. Это может работать случайно, но это, конечно, не то, что вы хотели бы сделать по своему замыслу. Вы либо захотите явно очистить свой буфер и вообще не спать, либо использовать какую-либо форму синхронизации.

Что касается того, почему printf не проявляет этих проблем ... ну, это дрянь. И printf, и cout используют некоторую форму буферизованного вывода, но реализация каждого из них может отличаться.

Таким образом, лучше запомнить следующее:

  • Если вы хотите синхронизировать, используйте примитивы синхронизации.
  • Если вы хотите дать кому-то еще шанс побежать, спите.
  • ОС лучше решает, блокирует ли операция ввода / вывода.
2 голосов
/ 18 марта 2009

Причина, по которой вызов в сон заставляет ваш код работать, заключается в том, что вы используете его для превращения потенциально параллельного выполнения двух действий выходного потока в одно последовательное действие. Вызов sleep () позволит планировщику переключиться на основной поток выполнения и выполнить поток A.

Если вы не включите sleep (), порядок выполнения потока не гарантируется, и поток B вполне может начать выполнение / печать до того, как поток A сможет это сделать.

1 голос
/ 18 марта 2009

В коде, запускающем два потока:

beginthread (threadA);
sleep(100);
beginthread (threadB);

sleep () ждет 100 мс и затем продолжается. Программист, вероятно, сделал это для того, чтобы дать возможность ThreadA запускаться перед запуском threadB. Если вам нужно дождаться инициализации и запуска threadA перед запуском threadB, вам нужен механизм, который ожидает запуска threadA, но это неправильный способ сделать это.

100 - это волшебное печенье, выбранное произвольно, возможно, сопровождающее мысль типа «не нужно запускать нитьА более 100 мсек». Подобные предположения ошибочны, потому что у вас нет возможности узнать, сколько времени потребуется для запуска threadA. Если машина занята или если реализация потока A изменяется, для запуска потока может потребоваться более 100 мс, запустить код запуска и перейти к основному циклу (если это поток такого типа).

Вместо того, чтобы спать в течение некоторого произвольного промежутка времени, threadA должен сообщить основному потоку, когда он запущен и работает. Один из распространенных способов сделать это - сообщить о событии.

Пример кода, который иллюстрирует, как это сделать:

#include "stdafx.h"
#include <windows.h>
#include <process.h>


struct ThreadParam
{
    HANDLE running_;
    HANDLE die_;
};

DWORD WINAPI threadA(void* pv)
{
    ThreadParam* param = reinterpret_cast<ThreadParam*>(pv);
    if( !param )
        return 1;

    // do some initialization
    //  :   :

    SetEvent(param->running_);
    WaitForSingleObject(param->die_, INFINITE);
    return 0;
}

DWORD WINAPI threadB(void* pv)
{
    ThreadParam* param = reinterpret_cast<ThreadParam*>(pv);
    if( !param )
        return 1;

    // do some initialization
    //  :   :

    SetEvent(param->running_);
    WaitForSingleObject(param->die_, INFINITE);
    return 0;
}

int main(int argc, char** argv) 
{
    ThreadParam 
        paramA = {CreateEvent(0, 1, 0, 0), CreateEvent(0, 1, 0, 0) },
        paramB = {CreateEvent(0, 1, 0, 0), CreateEvent(0, 1, 0, 0) };

    DWORD idA = 0, idB = 0;
    // start thread A, wait for it to initialize
    HANDLE a = CreateThread(0, 0, threadA, (void*)&paramA, 0, &idA);
    WaitForSingleObject(paramA.running_, INFINITE);
    // start thread B, wait for it to initi
    HANDLE b = CreateThread(0, 0, threadB, (void*)&paramB, 0, &idB);
    WaitForSingleObject(paramB.running_, INFINITE);
    // tell both threads to die
    SetEvent(paramA.die_);
    SetEvent(paramB.die_);
    CloseHandle(a);
    CloseHandle(b);
    return 0;
}
1 голос
/ 18 марта 2009
while( true )
{
   msgStack.Lock();
   process( msgStack.pop_msg());   
   msgStack.Unlock();
   sleep(0);
}
1 голос
/ 18 марта 2009

Если у вас проблемы с отображением печатного текста "abcd", это потому, что вы не даете cout символ конца строки для очистки буфера.

если поставить

cout << "abcd" << endl;

вы сможете увидеть символы, тогда он издаст звуковой сигнал. спать не нужно.

1 голос
/ 18 марта 2009

сон в первом примере - это просто напечатать сообщение немного, прежде чем вы увидите действие «возврат» Во втором примере сон "может" помочь. Но это странно. Вы не сможете синхронизировать консольные выходы со сном в некоторых более сложных случаях.

0 голосов
/ 18 марта 2009

Сон можно использовать, чтобы избежать определенного потока / процесса (да, я знаю, что это разные вещи), загружающего процессор.

С другой стороны, printf является потокобезопасным. Кута нет. Это может объяснить различия в их поведении.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...