Синхронизация 2х потоков
Есть 2 потока которые выполняют след. функции.
void f2() {
auto logger = getLogger("log.txt", "f2"); // Log to file with name log.txt. Each message has f2 prefix
// File output: 23.02.2020 18:06:06; DEBUG; f2(3444): Running a thread
logger(DEBUG) << "Running a thread";
double timeSpent = 10.0;
// File output: 23.02.2020 18:06:06; WARNING; f2(3444): Time spent in the thread: 10.0 seconds
logger(WARNING) << "Time spent in the thread: " << timeSpent << " seconds";
}
void f3() {
auto logger = getLogger("log2.txt", "f3"); // Log to file with name log2.txt. Each message has f3 prefix
// File output: 23.02.2020 18:06:06; INFO; f3(3444): Running a thread
logger << "Running a thread"; // Default log level INFO
int i = 123;
// File output: 23.02.2020 18:06:06; ERROR; f3(3444): My int is 123;
logger(ERROR) << "My int is " << i;
}
Реализация функции getLogger()
auto getLogger(const char* file, const char* pref = " ")
{
logclass a(file, pref);
if (LOGFILE.is_open()) LOGFILE.close();
LOGFILE.open(file, ios::app);
return a;
}
В классе logclass перегружены операторы << и ()
ostream& logclass::operator () (loglevels level)
{
ostream& os = filename ? LOGFILE : cout;
time_t t = time(0);
tm* now = localtime(&t);
lock_guard<mutex> lock(g_lock);
os << endl << now->tm_mday << "/" << now->tm_mon << "/" << 1900 + now->tm_year;
os << ", " << now->tm_hour << ":" << now->tm_min << ":" << now->tm_sec << ": ";
switch (level)
{
case INFO:
os << "INFO; ";
if (prefix) os << prefix;
os << "(" << this_thread::get_id() << ") ";
return os;
case DEBUG:
os << "DEBUG; ";
if (prefix) os << prefix;
os << "(" << this_thread::get_id() << ") ";
return os;
case WARNING:
os << "WARNING; ";
if (prefix) os << prefix;
os << "(" << this_thread::get_id() << ") ";
return os;
case ERROR:
os << "ERROR; ";
if (prefix) os << prefix;
os << "(" << this_thread::get_id() << ") ";
return os;
}
}
template <class T>
void operator << (logclass& a, T smth)
{
ostream& os = a.filename ? LOGFILE : cout;
time_t t = time(0);
tm* now = localtime(&t);
lock_guard<mutex> lock(g_lock);
os << endl << now->tm_mday << "/" << now->tm_mon << "/" << 1900 + now->tm_year;
os << ", " << now->tm_hour << ":" << now->tm_min << ":" << now->tm_sec << ": ";
if (a.prefix) os << "INFO; " << a.prefix << "(" << this_thread::get_id() << ") " << smth;
else os << "INFO; " << "(" << this_thread::get_id() << ") " << smth;
}
Не имею ни малейшего понятия как их правильно синхронизировать, нужна помощь.
Ответы (1 шт):
Автор решения: Chorkov
→ Ссылка
У вас мутексом защищено не все предложение вывода строк, а только та часть которая находится внутри logclass::operator (). Для того чтобы защитить весь блок вывода, нужно возвращать из logclass::operator () како-то временный объект, тогда в его деструкторе можно будет определить что предложение окончено и снять блокировку. Например:
struct locked_ostream
{
std::ostream& os;
std::unique_lock<std::mutex> lock;
template< typename T>
std::ostream& operator<< ( const T& rhs ) const
{
return os<<rhs;
}
};
locked_ostream logclass::operator () (loglevels level)
{
std::ostream& os = std::cout;
std::unique_lock<std::mutex> lock(g_lock);
...
return locked_ostream{ os, std::move(lock) };
}