[Solved] Системные часы в отдельном процессе fork() или pthread_create() ?

Модератор: Модераторы разделов

Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

[Solved] Системные часы в отдельном процессе fork() или pthread_create() ?

Сообщение sabir »

Привет всем!
Совершенно неожиданно у меня возник вопрос, а как ПРАВИЛЬНО(!) написать простейшую консольную программку-часы на голом цэ.
Есть два варианта, оба работают, однако есть пара вопросов.

Вариант №1.

Код: Выделить всё

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

void update_clock()
{
    char buf_time[40];
    struct timeval time_clock;

    gettimeofday(&time_clock, 0);
    strftime(buf_time, sizeof(buf_time), "%H:%M:%S", localtime(&time_clock.tv_sec));
    printf("%s\n", buf_time);
}

int main()
{
    fd_set fd;
    struct timeval tv;
    time_t now;
    struct tm *lt;

    update_clock();

    while(1)
    {
        now = time(0);
        lt = gmtime(&now);
        tv.tv_usec = 0;
        tv.tv_sec = 60 - lt->tm_sec;
        FD_ZERO(&fd);
        FD_SET(0, &fd);
        if(select(1, &fd, 0, 0, &tv) == 0) update_clock();
    }

    return 0;
}

Ровно раз в минуту, как и ожидается, синхронно с часами в lxpanel, выводится время, это именно то, что мне и нужно.

Вариант №2.

Код: Выделить всё

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

void update_clock()
{
    char buf_time[40];
    struct timeval time_clock;

    gettimeofday(&time_clock, 0);
    strftime(buf_time, sizeof(buf_time), "%H:%M:%S", localtime(&time_clock.tv_sec));
    printf("%s\n", buf_time);
}

int main()
{
    while(1)
    {
        update_clock();
        sleep(1);
    }

    return 0;
}

Тоже работает.
Так что лучше, какой вариант, критерий оценки = наименьшая нагрузка на камень и наименьший расход ресурсов.

Ну и пара вопросов:

Q1: Есть ли другие варианты, при условии, что это будет голый цэ, а еще лучше голые syscall'ы + asm?
Задача вывод точного времени, не просто раз в минуту, а синхронно с системными часами, т.е. было 12:30, и вдруг раз и стало 12:31, как правильно поймать это событие?

Q2: Как бы выщелкнуть цикл проверки и печати в отдельный процесс/нить?
Задача проста, есть цикл главной программы и он НИЧЕГО не делает, кроме как проверяет, а не завис ли дочерний процесс/нить и если завис, то убить его и запустить заново.
Что лучше/правильнее fork() или pthread_create().
Насколько я понимаю, fork() запускает дочерний процесс как абсолютную копию родительского, за исключением другого PID, можно ли запустить дочерний процесс и заставить его выполнять ТОЛЬКО одну задачу/функцию (НЕ отдельный бинарь, а именно процесс/нить), которую родительский процесс НЕ выполняет, ну например печать системного времени. Или спецом для таких задач и придуман pthread_create()?
В псевдо коде это что то типа:

Код: Выделить всё

main()
{
    fork() / pthread_create(): update_clock();

    while(1)
    {
        if(!проверка_дочернего_процесса/нити())
        // процесс/нить не отвечает == завис
        kill(): update_clock();
        restart(): update_clock();
    }

    return 0;
}

Я вообще туда копаю или есть более простые решения?
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: [Solved] Системные часы в отдельном процессе fork() или pthread_create() ?

Сообщение drBatty »

sabir писал(а):
24.10.2014 01:12
что лучше

второй вариант мне больше нравится(не вдавался особо).
sabir писал(а):
24.10.2014 01:12
Задача вывод точного времени, не просто раз в минуту, а синхронно с системными часами, т.е. было 12:30, и вдруг раз и стало 12:31, как правильно поймать это событие?

ИМХО надо брать более точное время(с тысячными и т.п.), ждать так, что-бы до события оставалось немного времени, и ПЕРЕД моментом стартовать бесконечный цикл ожидания. Насколько раньше? ИМХО на 1..2 единицы системного таймера в ядре.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

Re: [Solved] Системные часы в отдельном процессе fork() или pthread_create() ?

Сообщение sabir »

drBatty писал(а):
25.10.2014 11:46
sabir писал(а):
24.10.2014 01:12
что лучше

второй вариант мне больше нравится(не вдавался особо).

Да, я тоже больше склоняюсь ко второму варианту, причем сразу по двум причинам:
1. Я совершенно не понимаю как работает первый вариант, а именно функция select()
2. Кроме системного времени, раз в секунду еще удобно проверять и печатать нагрузку на камень, размер свободной и занятой памяти, сетевую активность, температуру, скорость вращения фанов и прочие мульки, ну навроде как системный монитор на голом це. А что, всего и делов то, пропарсить пару файликов в /proc/* и printf'нуть на экран в нужном месте в нужное время.
Кстати, а есть ли альтернатива /proc/*, я имею ввиду вместо того, что бы парсить /proc/meminfo для выяснения а скока там у нас памяти то осталось, может есть какие спец syscall'ы (вроде как нет) или libc'колы. Гугл говорит что парсить /proc/* в Linux это норма, но может я что пропустил, лениво программно ковыряться в текстовом файле, куда как проще вызвать готовые функции, если они конечно предусмотрены девелоперами www.kernel.org :)
Например что то вроде:

Код: Выделить всё

#include <stdio.h>
#include <sys/utsname.h>

main()
{
    struct utsname usys;
    uname(&usys);
    printf("OS: %s, %s, %s, %s\n", usys.sysname, usys.release, usys.version, usys.machine);
}

Выдает:

Код: Выделить всё

OS: Linux, 3.17.1-porteus, #1 SMP PREEMPT Tue Oct 21 12:11:34 MSK 2014, x86_64

Т.о. мы видим, что функция uname() спецом заточена для парсения файлика /proc/version.
или

Выдает:

Код: Выделить всё

             total       used       free     shared    buffers     cached
Mem:          6920       6710        210          0       1424       4603
-/+ buffers/cache:        682       6237
Swap:            0          0          0

Тока вызывать "free" при помощи /bin/sh это скриптинг, а мне надо кодинг, т.е. нужна функция типа ufree(), если проводить аналогию с uname(), но такой нету, или все же есть?
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5427
ОС: Gentoo

Re: [Solved] Системные часы в отдельном процессе fork() или pthread_create() ?

Сообщение /dev/random »

По нулевому вопросу: второй вариант просыпается и дёргает часы раз в секунду. Соответственно, точность обновления тут ±1 секунда, и повысить её можно лишь путём напрасного расхода CPU. Если вас устраивает такая точность, используйте этот вариант, т.к. он самый простой. У первого же варианта в данном случае точность такая же (±1 сек), но её легко нарастить безо всяких потерь. Суть этого варианта в следующем: он смотрит текущее время, вычисляет, сколько осталось до переключения (в данном случае - с точностью до секунды, устанавливая 0 в поле микросекунд, но это легко изменить) и засыпает ровно на столько времени. До тех пор часы не дёргает. Очень эффективный метод, но имеет недостаток. Если до переключения минуты оставалось, скажем, 50 сек, а вы перевели часы так, что теперь остаётся 10 сек, программа всё равно проснётся только через 50. Да, и ещё: функция select() без передачи файловых дескрипторов здесь используется просто в качестве кроссплатформенного аналога usleep(). Будет выглядеть гораздо понятнее, если заменить select() на usleep(), но последняя есть не во всех операционках.

По первому вопросу (Q1): Если вы для отрисовки часов пользуетесь тулкитом, в котором есть концепция "главного цикла", то есть и третий, более предпочтительный вариант: установить таймеры-обработчики в главный цикл. Как это делается - зависит от тулкита. Если же вы просто делаете printf(), как в примерах, то любой имеющийся у вас вариант (кроме совсем уж переусложнённых) будет просто вариацией на тему первых двух.

По второму вопросу (Q2): Всё зависит от того, зачем вам эта многопоточность, чего именно вы хотите добиться. Без информации о ваших целях ответить на вопрос нельзя.

И по последнему вопросу, который в отдельном сообщении: по-хорошему, его следовало задать в отдельной теме. Но всё же отвечу. Кроссплатформенных способов получить эту информацию нет. В Linux нужно парсить /proc. При желании, можете воспользоваться готовыми библиотеками, которые распарсят его за вас, например, libprocps.
Спасибо сказали:
Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

Re: [Solved] Системные часы в отдельном процессе fork() или pthread_create() ?

Сообщение sabir »

/dev/random писал(а):
26.10.2014 08:53
По второму вопросу (Q2): Всё зависит от того, зачем вам эта многопоточность, чего именно вы хотите добиться. Без информации о ваших целях ответить на вопрос нельзя

Благодарю за подробный ответ.
А что касаемо цели по второму вопросу, то многопоточность штука интересная и много где может быть заюзана, а если конкретный пример, то что то вроде:

Код: Выделить всё

int main()
{
    while(1)
    {
        ...
    }
}

Т.е. имеется тело программы с бесконечным циклом. Есть, например, следующие задачи, которые должны делаться одновременно и не зависимо друг от друга:
1. Раз в секунду проверять и печатать загруженность CPU, памяти и пр. (системный монитор)
2. Раз в минуту печатать системное время (часы)
3. Раз в 10 минут проверять нажимались ли кнопки на клаве и двигалась ли мышка, если нет погасить моник (скринсейвер)
4. Какой нибудь планировщик, скажем раз в час напоминает, пора спать, завтра на работу, хватит торчать за компом
5. Постоянное ожидание события втыкания флешки или сидюка, которое может быть никогда и не произойдет
Таким образом в один цикл их не запихнуть или если и можно, то с ненужными сложностями. Вот мне и думается, что главный цикл должен только контролировать дочерние процессы или нити, которые в свою очередь и будут выполняют всю грязную работу. Таким образом сама программа зависнуть не сможет, просто потому, что она ничего не делает, а если зависнет дочерний процесс, то его легко убить и перезапустить.
Ну или скажем оконный менеджер, он один, а окон скажем 200 и в каждом окне происходят некие события с НЕ одинаковой частотой на которые нужно реагировать прям щас, в одном цикле обработать их все гиморойно, пока будем рисовать одно окно, остальные будут стоять, а в них тоже может что то меняться, а так создал юзер окно, менеджер окон создал отдельный процесс под это окно, процесс следит за окном, а менеджер окон следит за процессами
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5427
ОС: Gentoo

Re: [Solved] Системные часы в отдельном процессе fork() или pthread_create() ?

Сообщение /dev/random »

sabir писал(а):
26.10.2014 20:41
Т.е. имеется тело программы с бесконечным циклом. Есть, например, следующие задачи, которые должны делаться одновременно и не зависимо друг от друга:
1. Раз в секунду проверять и печатать загруженность CPU, памяти и пр. (системный монитор)
2. Раз в минуту печатать системное время (часы)
3. Раз в 10 минут проверять нажимались ли кнопки на клаве и двигалась ли мышка, если нет погасить моник (скринсейвер)
4. Какой нибудь планировщик, скажем раз в час напоминает, пора спать, завтра на работу, хватит торчать за компом
5. Постоянное ожидание события втыкания флешки или сидюка, которое может быть никогда и не произойдет
Таким образом в один цикл их не запихнуть или если и можно, то с ненужными сложностями. Вот мне и думается, что главный цикл должен только контролировать дочерние процессы или нити, которые в свою очередь и будут выполняют всю грязную работу. Таким образом сама программа зависнуть не сможет, просто потому, что она ничего не делает, а если зависнет дочерний процесс, то его легко убить и перезапустить.

Это же тривиальные задачи, как их можно заставить зависнуть? Вы скорее что-нибудь напутаете в проверке "а не завис ли рабочий поток", чем в этих задачах.

sabir писал(а):
26.10.2014 20:41
Ну или скажем оконный менеджер, он один, а окон скажем 200 и в каждом окне происходят некие события с НЕ одинаковой частотой на которые нужно реагировать прям щас, в одном цикле обработать их все гиморойно, пока будем рисовать одно окно, остальные будут стоять, а в них тоже может что то меняться, а так создал юзер окно, менеджер окон создал отдельный процесс под это окно, процесс следит за окном, а менеджер окон следит за процессами

Программы, владеющие окнами, отрисовывают эти окна сами. Нечто подобное описанному у вас происходит только если оконный менеджер композитный. В этом случае программы рисуют не прямо на экране, а в отдельных буферах, а композитник объединяет содержимое буферов на экране. Но параллельности в этом объединении нет. Окна должны корректно перекрывать друг друга, поэтому помещаются на экран в строго определённом порядке, а не наперегонки.

Тем более, что это не является ответом на мой вопрос. Я спрашивал, зачем параллельность лично вам, в данном, конкретном случае, а не зачем она может понадобиться в принципе. Вы же не собираетесь писать оконный менеджер? Дело в том, что в одних случаях лучше fork(), в других - pthread_create(), и вне контекста нельзя сказать, что вам лучше выбрать, и как именно их лучше использовать. Более того, если оставить задачу как есть, как вы её описали в первом сообщении, то любая параллельность будет излишним переусложнением.

Если же вы просто хотите научиться писать многопоточные/многопроцессные программы, то и выбирайте то, чему хотите научиться. Вопрос "что лучше" здесь неуместен: в описанной вами задаче и то, и другое плохо.
Спасибо сказали:
Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

Re: [Solved] Системные часы в отдельном процессе fork() или pthread_create() ?

Сообщение sabir »

/dev/random писал(а):
27.10.2014 07:34
Вы же не собираетесь писать оконный менеджер?

Вы будете смеяться, но именно это я и делаю, оконный+композитный менеджер в одном флаконе. Да-да, я знаю о существовании Xlib, и что самому не надо этого делать, и что это изобретение велосипеда. Мне просто интересно как можно реализовать подобную задачу с нуля, без претензий на мировое признание, а также в рамках изучения программирования под Linux, что то ведь надо делать руками, чтение книжек не заменит практики.
Тему можно закрывать, я нашел в гугле пару статей, там есть все что я хотел узнать о fork() и pthread_create(). Называется Программирование для Linux. Части 6-7. Автор Андрей Боровский.
Спасибо сказали:
Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

Re: [Solved] Системные часы в отдельном процессе fork() или pthread_create() ?

Сообщение sabir »

sabir писал(а):
27.10.2014 17:21
Тему можно закрывать, я нашел в гугле пару статей, там есть все что я хотел узнать о fork() и pthread_create(). Называется Программирование для Linux. Части 6-7. Автор Андрей Боровский.

Вот простой пример того, о чем я спрашивал

Код: Выделить всё

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

void * update_clock(void *arg)
{
    char buf_time[40];
    struct timeval time_clock;

    while(1)
    {
        gettimeofday(&time_clock, 0);
        strftime(buf_time, sizeof(buf_time), "%H:%M:%S", localtime(&time_clock.tv_sec));
        printf("%s\n", buf_time);
        sleep(1);
    }
}

int main()
{
    pthread_t thread;
    int id = 1;
    int result = 0;

    result = pthread_create(&thread, NULL, update_clock, &id);
    if(result != 0)
    {
        printf("Create thread failed\n");
        return -1;
    }

    while(1)
    {
        printf("Show goes on!\n");
        sleep(10);
    }

    return 0;
}

Печать системного времени осуществляется в отдельном потоке, в то время как основная программа занята своей собственной работой. Может это и не нужно, но именно это я и хотел узнать :)
За рамками решения осталась проверка потока за зависание, но в данном случае это не нужно, решать проблемы лучше по мере их поступления.

То же самое, но с использованием fork()

Код: Выделить всё

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

void update_clock()
{
    char buf_time[40];
    struct timeval time_clock;

    while(1)
    {
        gettimeofday(&time_clock, 0);
        strftime(buf_time, sizeof(buf_time), "%H:%M:%S", localtime(&time_clock.tv_sec));
        printf("%s\n", buf_time);
        sleep(1);
    }
}

int main(int argc, char ** argv)
{
    int pid = fork();

    // Если pid == 0, то это дочерний процесс
    if(pid == 0) update_clock();
    // Иначе - родительский процесс
    else
    {
        while(1)
        {
            printf("Show goes on!\n");
            sleep(10);
        }
    }
    return 0;
}
Спасибо сказали:
Аватара пользователя
sabir
Сообщения: 66
ОС: OpenBSD

Re: [Solved] Системные часы в отдельном процессе fork() или pthread_create() ?

Сообщение sabir »

sabir писал(а):
26.10.2014 00:30
Кстати, а есть ли альтернатива /proc/*, я имею ввиду вместо того, что бы парсить /proc/meminfo для выяснения а скока там у нас памяти то осталось, может есть какие спец syscall'ы (вроде как нет) или libc'колы. Гугл говорит что парсить /proc/* в Linux это норма, но может я что пропустил, лениво программно ковыряться в текстовом файле, куда как проще вызвать готовые функции, если они конечно предусмотрены девелоперами www.kernel.org :)

Да есть конечно же, тока об этом не принято говорить вслух, т.к. это не "кроссплатформенно", ну а ежели, к примеру, на кросплатформенность, мягко говоря, плевать, то встречайте syscall, называется sysctl(), выдает все, ну или почти все, характеристики ядра и пр.
На сегодняшний день я имею честь и удовольствие работать в OpenBSD, давно собирался соскочить с Linux и вот наконец то. Это я к тому, что уверенности, что это будет работать под Linux, у меня нет совершенно никакой.
Вот собственно пример кода, напрямую юзающего syscall, без парсинга текстовых файлов:

Код: Выделить всё

// main.c
// компилим как всегда: gcc main.c -o main

#include <stdio.h>
#include <sys/sysctl.h>

int main()
{
    int64_t bytes;
    int mib[2];
    size_t len = sizeof(bytes);

    // Get the Physical memory size
    mib[0] = CTL_HW;
    mib[1] = HW_PHYSMEM64;

    sysctl(mib, 2, &bytes, &len, NULL, 0);
    int megs = bytes / 1024 / 1024;
    printf("PHYS MEM: %d MiB\n", megs);

    return 0;
}

На моем компе выдает следующий результат:

Код: Выделить всё

PHYS MEM: 7089 MiB

И тут фашисты обманули, впрочем как и всегда, покупал 8 GiB памяти, а в наличии:
7089 / 1024 = 6.9228515625 GiB :D
Спасибо сказали: