2010-12-14 3 views
1

Можно ли предоставить пример кода для синхронизации, когда к конкретному файлу журнала обращаются несколько потоков. Я слышал об использовании объекта критического раздела, но не понял, как использовать его.Синхронизация файла журнала ошибок C++ по потоку

+1

Вы используете любую библиотеку для многопоточности (boost, Qt, ...)? Какой файл журнала вы используете? Как раз для Fstream или пользовательского класса? – Philipp

ответ

4

Информация о реализации будет зависеть от того, какая платформа (Win32, Posix, ...) вы есть, и от какой библиотеки вы используете (QT, boost, ...). Однако общая идея будет такой же, как и примитив, который вы можете использовать, с эквивалентами.

Это series of articles должно дать вам хорошее представление о доступной опции на другой платформе и каковы эквивалентности.

При этом вы должны быть в состоянии написать CriticalSection класс:

class CriticalSection 
{ 
    // System specific object 

public: 
    CriticalSection(); 
    ~CriticalSection(); 

    void Lock(); 
    void Unlock(); 
}; 

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

static CriticalSection gLogFileCS; 
static std::ofstream* gLogFilePtr; 

void SendLogMessage(const char* message) 
{ 
    gLogFileCS.Lock(); 
    gLogFilePtr->write(message); 
    gLogFileCS.Unlock(); 
} 

Вы должны, вероятно, использовать RAII, чтобы убедиться, что вы всегда разблокировать CriticalSection, когда вы сделали с ним. Вы напишете CriticalSectionScopeLock класс,

class CriticalSectionScopeLock 
{ 
    CriticalSection& CriticalSection_; 

public: 
    CriticalSectionScopeLock(CriticalSection& cs) 
    : CriticalSection_(cs) 
    { 
     cs.Lock(); 
    } 

    ~CriticalSectionScopeLock() 
    { 
     cs.Unlock(); 
    } 
}; 

, а затем функция SendLogMessage можно переписать так:

void SendLogMessage(const char* message) 
{ 
    CriticalSectionScopeLock lock(gLogFileCS); 
    gLogFilePtr->write(message); 
} 

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

enum MessageType 
{ 
    MessageQuit, 
    MessageLog, 
}; 

struct LogThreadMessage 
{ 
    MessageType type; 
    char*  data; 
}; 

static CriticalSection gLogThreadQueueCS; 
static std::list<LogThreadMessage> gLogThreadQueue; 

void StartupLogThread(const char* filename) 
{ 
    // System specific stuff to create a thread, and have 
    // it run the LogThreadLoop function. 
} 

static void LogThreadLoop(std::ostream& logFile) 
{ 
    for (;;) 
    { 
     std::list<LogThreadMessage> queue; 
     { 
      CriticalSectionScopeLock lock(gLogThreadQueueCS); 
      queue.swap(gLogThreadQueue); 
     } 

     while (!queue.empty()) 
     { 
      LogThreadMessage msg = queue.front(); 
      queue.pop_front(); 

      switch (msg.type) 
      { 
       case MessageQuit: 
        return; 

       case MessageLog: 
        logFile.write(msg.data); 
        break; 
      } 
     } 

     sleep(10); 
    } 
} 

void PostLogThreadMessage(const LogThreadMessage& msg) 
{ 
    CriticalSectionScopeLock lock(gLogThreadQueueCS); 
    gLogThreadQueue.insert(gLogThreadQueue.end(), msg); 
} 

void SendLogMessage(char* message) 
{ 
    LogThreadMessage msg; 
    msg.type = MessageLog; 
    msg.data = message; 

    PostLogThreadMessage(msg); 
} 

void StopLogThread() 
{ 
    LogThreadMessage msg; 
    msg.type = MessageLog; 
    msg.data = message; 

    PostLogThreadMessage(msg); 
} 
+0

очень хороший ответ – patriiice

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