Как создать в безопасном многопоточном окружении класс для вывода информации о работе программы в консоль и в файл? Какие методы можно использовать для обеспечения безопасности работы класса в многопоточной среде? Желаемо сохранить цельные сообщения при выводе информации.
Этот класс может быть использован в многопоточной среде безопасно, если обеспечить синхронизацию доступа к его методам.
Для создания класса, который может выводить информацию как в консоль, так и в файл в безопасном многопоточном окружении, можно использовать концепцию мьютексов или блокировок.
Вот пример простого класса, который выполняет такую задачу:
```java
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Logger {
private PrintWriter consoleWriter;
private PrintWriter fileWriter;
private Lock lock = new ReentrantLock();
public Logger(String filename) {
try {
consoleWriter = new PrintWriter(System.out, true);
fileWriter = new PrintWriter(new FileWriter(filename), true);
} catch (IOException e) {
e.printStackTrace();
}
}
public void log(String message) {
lock.lock();
try {
consoleWriter.println(message);
fileWriter.println(message);
} finally {
lock.unlock();
}
}
public void close() {
consoleWriter.close();
fileWriter.close();
}
}
```
В данном примере используется мьютекс `ReentrantLock`, чтобы обеспечить синхронизированный доступ к методу `log()`, который выводит информацию как в консоль, так и в файл. Мьютекс блокирует доступ к методу другим потокам, пока один поток не завершит свою операцию.
Таким образом, использование блокировок или мьютексов позволяет обеспечить безопасность работы класса в многопоточной среде и сохранить цельные сообщения при выводе информации.
Не безопасен.
Вы защитили мьютексом только запись в очередь (push), но не чтение из нее (pop). Так что очередь сломается рано или поздно.
Вообще тут лучше бы подошла какая-то специализированная структура со встроенной поддержкой многопоточности, а не стандартные контейнеры.
Можно использовать кольцевой буфер или очередь майкла-скотта. В booste, на сколько помню, есть и то и другое.
Но для начала сгодится и такой вариант.
Кроме того для вывода на экран в Линукс можно учитывать тот факт, что ОС обеспечивает атомарную запись в консоль для буфера менее PIPE_BUF байт. https://linux.die.net/man/7/pipe
Думаю в винде то же есть похожая гарантия, но это не точно.
Кроме того, операция<<для логгирования не очень подходит, т.к. вынуждает использовать конструкции типа:oss << "Error: " << strerror(err) << "(" << err << ")";
для вывода 1 строки. А это уже не одна запись в очередь, а несколько. Так что защита мьютексом тут не будет гарантией вывода целостной строки.
Для логгера больше подойдет вариант типа std::printf, когда в один вызов передается вся информация для генерации целой строки.