2014-02-13 3 views
1

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

import std.stdio; 
import std.exception; 
import std.conv; 

@trusted: 

enum LogLevel { 
    NONE, 
    ERROR, 
    WARN, 
    INFO, 
    DEBUG, 
} 

synchronized class Logger { 

    LogLevel level = LogLevel.WARN; 

    // The File* must be shared since this is a synchronized class 
    @property shared(File*) output() { return to; } 

    @property void output(shared(File*) f) 
    { 
     enforce(f != null); 
     to = f; 
    } 

    void log(LogLevel l)(string message, string file = __FILE__, int line = __LINE__) 
    { 
     if(l < level) 
      return; 

     to.writeln(l.to!string, ": ", message, "(", file, ":", line.to!string, ")"); 
    } 

    alias log!(LogLevel.ERROR) logError; 
    alias log!(LogLevel.WARN) logWarn; 
    alias log!(LogLevel.INFO) logInfo; 
    alias log!(LogLevel.DEBUG) logDebug; 

private: 
    File* to = &stdout; 
} 

Однако, по-видимому File.writeln не очень приятно быть синхронизированы. Я поздоровался со следующей ошибкой из ДМД:

log.d(32): Error: template std.stdio.File.writeln does not match any function template declaration. Candidates are:
/usr/include/dlang/dmd/std/stdio.d(781): std.stdio.File.writeln(S...)(S args)

Что такое правильный способ обеспечить общий доступ к файлу через несколько потоков? Некоторые первоначальные мысли:

  1. В Alexandrescu-х Д Язык программирования, он упоминает, что writeln на stout атомарно по отношению к выходному потоку, но я не могу найти, что где-нибудь в онлайн-документации.

  2. Даже если точка 1 истинна, не хочу ли я, чтобы класс Logger был синхронизирован ради свойства вывода?

ответ

3

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

void log(LogLevel l)(string message, string file = __FILE__, int line = __LINE__){ 
    locate("logger").send(l,message,file,line); 
} 

то поток будет:

void loggerLoop(){ 
    //setup file and such 
    register(thisTid, "logger"); 
    scope(exit)unregister("logger"); 
    while(true){ 
     receive((LogLevel l,string message, string file, int line){ 
      if(l < level) 
       return; 
      to.writeln(l.to!string, ": ", message, "(", file, ":", line.to!string, ")"); 
     } 
    } 
} 
+0

Хорошо, но как бы один проход, который 'File *' (т.е. 'to' в вашем примере) для входа? Учитывая, что мои параметры состоят в том, чтобы сделать поток файлов локальным или неизменным (что запрещало бы писать ему), невозможно ли делиться файлом между потоками? Что делать, если я хочу использовать stdout в качестве файла? Я, конечно, хочу иметь возможность печатать как из логгера, так и из других источников. –

+0

Обычно это делается в файле конфигурации logger ... – DejanLekic

+0

@DejanLekic Это, кроме того, точка. Опять же, что, если я хочу использовать stdout в качестве файла? Я, конечно, хочу иметь возможность печатать на нем от остальной части моей программы, а не только от журнала, что подразумевает, что я хотел бы, чтобы какой-то способ для нескольких потоков делил один дескриптор «Файл». –

Смежные вопросы