Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Многопоточность, printf


Автор: lv151 9.11.2011, 16:48
Cуществует ли "потокобезопасный" printf?

Автор: azesmcar 9.11.2011, 17:12
Цитата(lv151 @  9.11.2011,  16:48 Найти цитируемый пост)
Cуществует ли "потокобезопасный" printf? 

Где? в C++ - нет! В текущем C++ вообще нет ничего потокобезопасного.
Может в какой нибудь библиотеке и есть.
Думаю написать свой не должно составить особого труда.

Автор: lv151 9.11.2011, 17:29
Может какая-нибудь winapi оббёртка?

Автор: azesmcar 10.11.2011, 07:50
Цитата(lv151 @  9.11.2011,  17:29 Найти цитируемый пост)
Может какая-нибудь winapi оббёртка? 

 smile 

Автор: lv151 10.11.2011, 08:08
 smile 

Автор: GremlinProg 10.11.2011, 12:26
Цитата(lv151 @  9.11.2011,  18:48 Найти цитируемый пост)
Cуществует ли "потокобезопасный" printf?

конечно существует:
Код

int mtprintf( char*pszFmt, ... ){
    va_list Args;
    int Result;
    //
    va_start( Args, pszFmt );
    ::EnterCriticalSection( &cs_printf );
    Result    = vprintf( pszFmt, Args );
    ::LeaveCriticalSection( &cs_printf );
    va_end( Args );
    return Result;
}

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

если такой метод понадобился, значит в логику проекта откуда-то заполз нехороший таракан

Автор: lv151 10.11.2011, 12:32
OK.

Автор: feodorv 12.11.2011, 11:10
Цитата(azesmcar @ 9.11.2011,  17:12)
В текущем C++ вообще нет ничего потокобезопасного.

За что ж Вы так((( Microsoft так старалась, чтобы всё было потокобезапасно smile 
Насколько я знаю, можно спокойно пользоваться printf из стандартной библиотеки безо всяких обёрток... Безопасно будет smile 

Автор: azesmcar 12.11.2011, 11:20
Цитата(feodorv @  12.11.2011,  11:10 Найти цитируемый пост)
За что ж Вы так((( Microsoft так старалась, чтобы всё было потокобезапасно  

А причем тут microsoft? printf - сишная функция.

Цитата(feodorv @  12.11.2011,  11:10 Найти цитируемый пост)
Насколько я знаю, можно спокойно пользоваться printf из стандартной библиотеки безо всяких обёрток... Безопасно будет

"Насколько я знаю" - это не аргумент, где это написано?
http://msdn.microsoft.com/en-us/library/wc7014hz(v=vs.71).aspx

Автор: alexvs11 12.11.2011, 11:47
основная проблема - перемешивание логов
эту проблему лекго решает критическая секция/мьютекс в юзерспейсе и спинлок в кернеле

Автор: azesmcar 12.11.2011, 12:05
Цитата(alexvs11 @  12.11.2011,  11:47 Найти цитируемый пост)
спинлок в кернеле

spinlock - это обыкновенное ожидание в цикле, он по определению никак не может быть в kernel-е.

Автор: alexvs11 12.11.2011, 12:10
azesmcar, под кернелом я подразумеваю код, усполняющийся ядром, ну драйвера там
так в чем проблема?

Автор: azesmcar 12.11.2011, 12:48
Цитата(alexvs11 @  12.11.2011,  12:10 Найти цитируемый пост)
azesmcar, под кернелом я подразумеваю код, усполняющийся ядром, ну драйвера там

critical section - пользовательские объекты, mutex-ы и semaphor-ы - объекты ядра.
Spinlock ожидание в цикле, причем тут ядро и драйверы?

Автор: alexvs11 12.11.2011, 15:17
Цитата(azesmcar @  12.11.2011,  12:48 Найти цитируемый пост)
Spinlock ожидание в цикле, причем тут ядро и драйверы? 

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

Автор: feodorv 13.11.2011, 10:00
Цитата(azesmcar @  12.11.2011,  11:20 Найти цитируемый пост)
А причем тут microsoft? printf - сишная функция.

Автор топика просил что-нибудь из WinAPI. Однако даже на современных юниксах printf потокобезопасен.


Цитата(azesmcar @  12.11.2011,  11:20 Найти цитируемый пост)
"Насколько я знаю" - это не аргумент

Согласен, но я очень осторожен в безапелляционных высказываниях)))


Цитата(azesmcar @  12.11.2011,  11:20 Найти цитируемый пост)
где это написано?

Главное, что там не написано про потокоопасность printf. Про виды стандартной библиотеки смотрите там же: http://msdn.microsoft.com/en-us/library/abx4dbyh%28v=vs.71%29.aspx. И чтобы быть уж на все 100% уверенным, лучше пользовать много-поточную версию LIBC. В ней абсолютно все вызовы стандартной библиотеки потокобезопасны.

Однако даже в однопоточной версии LIBC printf потокобезопасна. Если хотите, продемонстрирую отрывками из исходных кодов LIBC (правда, прилагающихся к VC++ 6.0, но можно поискать и посвежее). Там внутри вызова как раз происходит обращения EnterCriticalSection/LeaveCriticalSection к одной из критических секций LIBC версии от Microsoft. Так что и перемешивания логов не будет smile 

Автор: GremlinProg 14.11.2011, 06:21
Цитата(feodorv @  13.11.2011,  12:00 Найти цитируемый пост)
Главное, что там не написано про потокоопасность printf.

сам printf не смотрел, может он и потокобезопасен (можно разобрать исходники),
но его основа - output, которой, например, я в основном и пользуюсь, точно не потокобезопасна и Microsoft в описании на это указывает:
Цитата

/***
*int _output(stream, format, argptr), static int output(format, argptr)
*
*Purpose:
*   Output performs printf style output onto a stream.  It is called by
*   printf/fprintf/sprintf/vprintf/vfprintf/vsprintf to so the dirty
*   work.  In multi-thread situations, _output assumes that the given
*   stream is already locked.
*
*   Algorithm:
*       The format string is parsed by using a finite state automaton
*       based on the current state and the current character read from
*       the format string.  Thus, looping is on a per-character basis,
*       not a per conversion specifier basis.  Once the format specififying
*       character is read, output is performed.
*
*Entry:
*   FILE *stream   - stream for output
*   char *format   - printf style format string
*   va_list argptr - pointer to list of subsidiary arguments
*
*Exit:
*   Returns the number of characters written, or -1 if an output error
*   occurs.
*ifdef _UNICODE
*   The wide-character flavour returns the number of wide-characters written.
*endif
*
*Exceptions:
*
*******************************************************************************/

Цитата(feodorv @  13.11.2011,  12:00 Найти цитируемый пост)
Так что и перемешивания логов не будет

перемешивание логов будет обязательно, иначе этот метод не потребовался бы,
причем этим перемешиванием желательно управлять хотя бы построчно, а еще лучше цветом,
иначе эта каша вывода будет бесполезна

Автор: GremlinProg 14.11.2011, 06:56
и, кстати, да, printf потокобезопасен:
printf.c:
Код

_lock_str2(1, stdout);

_file.c:
Код

void __cdecl _lock_file2 (
        int i,
        void *s
        )
{
        /*
         * The way the FILE is locked depends on whether it is part of _iob[]
         * _iob[] or not
         */
        if ( i < _IOB_ENTRIES )
        {
            /*
             * FILE lies in _iob[] so the lock lies in _locktable[].
             */
            _lock( _STREAM_LOCKS + i );
            /* We set _IOLOCKED to indicate we locked the stream */
            ((FILE*)s)->_flag |= _IOLOCKED;
        }
        else
            /*
             * Not part of _iob[]. Therefore, *s is a _FILEX and the
             * lock field of the struct is an initialized critical
             * section.
             */
            EnterCriticalSection( &(((_FILEX *)s)->lock) );
}

mlock.c:
Код

void __cdecl _lock (
        int locknum
        )
{

        /*
         * Create/open the lock, if necessary
         */
        if ( _locktable[locknum].lock == NULL ) {

            if ( !_mtinitlocknum(locknum) )
                _amsg_exit( _RT_LOCK );
        }

        /*
         * Enter the critical section.
         */

        EnterCriticalSection( _locktable[locknum].lock );
}

так что feodorv скорее прав, можно и без оберток )

Автор: feodorv 14.11.2011, 07:37
GremlinProg, спасибо  smile 

Автор: alexvs11 14.11.2011, 09:58
GremlinProg, это что и вообще откуда?
в любом  случае это отдельно взятая реализация, которая в другой версии компилятора совершенно другая и ничем не обязана

Автор: GremlinProg 14.11.2011, 10:42
Цитата(alexvs11 @  14.11.2011,  11:58 Найти цитируемый пост)
это что и вообще откуда?

это статическая реализация CRT из MSVS 2010
Цитата(alexvs11 @  14.11.2011,  11:58 Найти цитируемый пост)
это отдельно взятая реализация, которая в другой версии компилятора совершенно другая и ничем не обязана

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

у нас раздел такой,
API от Microsoft превалирует

Автор: Alexeis 14.11.2011, 11:04
Цитата(GremlinProg @  14.11.2011,  11:42 Найти цитируемый пост)
если в стандарте нет оговорок по поводу потоков

  А разве С++ что-то знает про потоки? В любом случае, если компилятор поставляется с многопоточной CRT, то проблем быть не должно. Думаю именно на это и нужно ориентироваться. 

Автор: xvr 14.11.2011, 16:25
Знаете, господа. Могу заявить по собственному опыту, что лог, порубленный в кашу посимвольво, конечно гораздо хуже читаем, чем порубленный в кашу построчно. Но извлечение полезной информации и из того и из другого, занятие достойное криптоаналитика  smile 
Так что не надо задаваться вопросом потокобезопасности printf'а, а надо разводить логи от разных потоков в разные файлы.  smile 

Автор: alexvs11 14.11.2011, 20:33
Цитата(xvr @  14.11.2011,  16:25 Найти цитируемый пост)
Так что не надо задаваться вопросом потокобезопасности printf'а, а надо разводить логи от разных потоков в разные файлы.

настоящий анализ начнется в попытках понять очередность их работы

Автор: Alexeis 14.11.2011, 21:54
Цитата(xvr @  14.11.2011,  17:25 Найти цитируемый пост)
Знаете, господа. Могу заявить по собственному опыту, что лог, порубленный в кашу посимвольво, конечно гораздо хуже читаем, чем порубленный в кашу построчно. Но извлечение полезной информации и из того и из другого, занятие достойное криптоаналитика

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

Автор: GremlinProg 15.11.2011, 07:03
Цитата(Alexeis @  14.11.2011,  23:54 Найти цитируемый пост)
  У меня примерно так работает лог, правда не в консоль вывод, а в файл. Из разных потоков пишут логи в кеш, который по таймауту или по наполнению сливается в один файл. Просматривая лог можно уловить последовательность операций. Пишется построчно, строки разных потоков чередуются, правда при этом каждый такой лог имеет префикс источника. 

а я так отлаживаю гибридные MPI-OpenMP-задачи, только пишу не в консоль и не в файл, а в сокет, определенному лог-серверу,
который все это дело показывает на своем десктопе в RTF-окнах

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

а префиксами выделяю лишь контекст задачи в пределах источника,

консоль конечно тоже вариант, но скудноватый, особенно, если потоков больше 8 ( цветов маловато, это затрудняет анализ разбора логов )

Автор: alexvs11 15.11.2011, 11:38
ну виндузятники к слову могут пользоваться OutputDebugString 
она и логов не перемешивает, и тайминг есть, и в WinDbg можно логи расскрашивать в сколь угодно цветов
ну и по сети логи снимать может

Автор: Alca 15.11.2011, 11:55
Цитата

настоящий анализ начнется в попытках понять очередность их работы

Ну так можно время писать в лог

Автор: xvr 15.11.2011, 11:55
Цитата(alexvs11 @  14.11.2011,  20:33 Найти цитируемый пост)
настоящий анализ начнется в попытках понять очередность их работы 

Я для этого использовал timestamp.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)