I'm using easylogging++ in my app to log messages for control and I've noticed that in production env (which runs under Linux) some messages were disappearing or missing from the log files. I managed to simulate this problem with a simple example in the test environment (on Windows). I made an infinite thread that just keeps on logging a counter and then I executed two instances of my program, here is a resumed example of my code:
#include "Log/Log.h"
#include <chrono>
#include <thread>
INITIALIZE_EASYLOGGINGPP
void log_test() {
long int count = 0;
while (true) {
log_info("Logando..." + std::to_string(count)); // this is defined in Log.h
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
count++;
}
}
int main(){
std::thread t(log_test);
t.detach();
// rest of the code
}
and Log.h/Log.cpp are:
#pragma once
#include "easylogging++.h"
#include <mutex>
static std::mutex mtx;
void log_info(std::string s);
void log_error(std::string s);
Log.cpp:
#include "Log.h"
void log_info(std::string s)
{
mtx.lock();
LOG(INFO, ELPP_THREAD_SAFE) << s;
mtx.unlock();
}
void log_error(std::string s)
{
mtx.lock();
LOG(ERROR, ELPP_THREAD_SAFE) << s;
mtx.unlock();
}
and the both executable files are using the same .conf file with the following configurations:
* GLOBAL:
FORMAT = "%datetime %msg"
FILENAME = "C:/logs/%datetime{%Y-%M-%d}/msgs.log"
ENABLED = true
TO_FILE = true
TO_STANDARD_OUTPUT = false
SUBSECOND_PRECISION = 6
PERFORMANCE_TRACKING = true
MAX_LOG_FILE_SIZE = 2097152 ## 2MB - Comment starts with two hashes (##)
in the msgs.log file I've noticed this sample:
2022-06-22 18:51:24,886631 Logando...288
2022-06-22 18:51:24,901856 Logando...289
2022-06-22 18:51:24,917820 Logando...5
2022-06-22 18:51:24,932827 Logando...291
2022-06-22 18:51:24,948248 Logando...292
Where the log 290 is missing from the first process and there's just this blank line instead. I guess that one solution could be just using different log files for each process, however it doesn't happen in one single process with multiple threads (instantiating thread t1, t2,t3 as in the code example before). I can't just change one log file to each process in production at the moment since it will have a high impact, so how can I solve it to I don't lose any message at all? Thanks in advance!
I guess that one solution could be just using different log files for each process, however it doesn't happen in one single process with multiple threads (instantiating thread t1, t2,t3 as in the code example before)
Well, threads in a single process share an instance of std::mutex mtx, so they're properly synchronized. Perhaps more importantly, the thing being correctly synchronized is access to a single buffer, which is the only buffer writing to your file.
Two processes will have completely independent instances of std::mutex mtx, which doesn't matter if they're single-threaded, because only one thread is writing to each process's buffer. The problem is that the two buffers are not synchronized with each other when writing to the file, and as mentioned in comments, these writes are apparently not atomic appends.
Solutions are:
Just use threads, since this works already.
Use a shared mutex - this is generally platform specific, but Boost.Interprocess is a good place to start.
Use two files - have some other process tail them both and combine into a single file if you need that
Use two FIFOs for the output files, and have some other process reading them both and combining them into a single file. It avoids duplicating the file storage on disk, but is probably *NIX specific.
Use network sinks (see the easyloggingc++ documentation), and have a process listening to two ports on localhost ... and combining them into a single file. More portable than FIFOs, but also more coding.
Related
It seems like boost::process::system is leaking fds:
Let's say I have this simple code to flush iptables config every 3 seconds (just an example):
#include <boost/process.hpp>
#include <thread>
int main(void)
{
while(true)
{
std::this_thread::sleep_for(std::chrono::seconds(3));
boost::process::system(boost::process::search_path("iptables"), "-F");
}
return 0;
}
If I observe the count of open file descriptors by listing /proc/PID/fd |wc -l, I can see that the count increases by one every 3 seconds. Eventually, when it reaches 1024, the program will abort, because the system call will throw an exception with what() stating that there are too many open files!
How can I avoid this fd leakage? I'm using boost 1.69.
EDIT:
Replacing boost::process::system with boost::process::child does not seem to help, the child seems to also leak fds, no matter if it gets detached or not.
EDIT 2:
Valgrind log with --track-fds=yes:
https://termbin.com/d6ud
The problem seems to be a bug in the specific version (1.69) of boost, and not in the posted code itself. So upgrading boost/patching the bug solves this problem.
The bug report can be found from here: https://github.com/boostorg/process/issues/62
Completely new to C++.
I'm comparing various aspects of C++, C# and Ruby to see if there's need for mirroring a library. Currently, simple read of a file (post update).
Compiling C++ and C# in VS 2017. C++ is in release(x64) mode (or at least compile then run)
The libraries more or less read a file and split the lines into three which make up the members of an object which are then stored in an array member.
For stress testing I tried a large file 380MB(7M lines) (after update) now getting similar performance with C++ and Ruby,
Purely reading the file and doing nothing else the performance is as below:
Ruby: 7s
C#: 2.5s
C++: 500+s (stopped running after awhile, something's clearly wrong)
C++(release build x64): 7.5s
The code:
#Ruby
file = File.open "test_file.txt"
while !file.eof
line = file.readline
end
//C#
StreamReader file = new StreamReader("test_file.txt");
file.Open();
while((line = file.ReadLine()) != null){
}
//C++
#include "stdafx.h"
#include "string"
#include "iostream"
#include "ctime"
#include "fstream"
int main()
{
std::ios::sync_with_stdio(false);
std::ifstream file;
file.open("c:/sandboxCPP/test_file.txt");
std::string line;
std::clock_t start;
double duration;
start = std::clock();
while (std::getline(file, line)) {
}
duration = (std::clock() - start) / (double)CLOCKS_PER_SEC;
std::cout << "\nDuration: " << duration;
while (true)
{
}
return 0;
}
Edit: The following performed incredibly well. 0.03s
vector<string> lines;
string tempString = str.str();
boost::split(lines, tempString, boost::is_any_of("\n"));
start = clock();
cout << "\nCount: " << lines.size();
int count = lines.size();
string s;
for (int i = 0; i < count; i++) {
s = lines[i];
}
s = on the likelihood that I don't know what boost is doing. Changed performance.
Tested with a cout of a random record at the end of the loop.
Thanks
Based on the comments and the originally posted code (it has now been fixed [now deleted]) there was previously a coding error (i++ missing) that stopped the C++ program from outputting anything. This plus the while(true) loop in the complete code sample would present symptoms consistent with those stated in the question (i.e. user waits 500s sees no output and force terminates the program). This is because it would complete reading the file without outputting anything and enter into the deliberately added infinite loop.
The revised complete source code correctly completes (according to the comments) in ~1.6s for a 1.2 million file. My advice for improving performance would be as follows:
Make sure you are compiling in release mode (not debug mode). Given the user has specified they are using Visual Studio 2017, I would recommend viewing the official Microsoft documentation (https://msdn.microsoft.com/en-us/library/wx0123s5.aspx) for a thorough explanation.
To make it easier to diagnose problems do not add an infinite loop at the end of your program. Instead run the executable from powershell / (cmd) and confirm that it terminates correctly.
EDIT: I would also add:
For accurate timings you also need to take into account the OS disk cache. Run each benchmark multiple times to 'warm-up' the disk cache.
C++ doesn’t automatically write everything the instant you tell it to. Instead, it buffers the data so it can write it all at once, which is usually faster. To say “I really want to write this now.”, you need to say something like std::cout << std::flush (if you use std::endl to end your lines it does this automatically).
Usually you don’t need to do this; the buffers are flushed when the program exits, or when you ask for input from the user, or things like that. However, your program doesn’t exit, so it never flushes its buffer. You read the input, and then the program is executing while(true) forever, never giving the output.
The solution to this is simple: remove the while loop at the end of the program. You should not have that; people usually assume a console program exits when it’s finished. I would’ve guessed you had that because Visual Studio automatically closed the console window when the program was finished, but apparently it doesn’t do that with Ctrl+F5, which you use, so I’m not sure.
My program has many different threads handling different things, and one of them deals with user input.
The other threads don't have much in the way of blocking calls, and those that do block are network based so will be interrupted or return gracefully when the socket is shut down.
However the user thread has calls to std::cin in order to grab the user input. The effect this has is while all the other threads are dead the user thread is still blocking on user input, and will only die the next time input is given.
Is there any way for me to check if there is any user input to grab before blocking?
I understand cin.peek() exists but from my experience, it blocks if there is nothing to read in. Assuming I'm using it correctly
My code is basically an infinite loop that stops when another thread switches the condition variable:
void doLoop()
{
while (running) //running is shared between all threads and all others die quickly when it is false. It's set to true before the threads are started
{
string input = "";
getline(cin, input);
//Handle Input
}
}
I'm on windows, using VS2013, and cannot use external libraries. I'm using windows.h and std throughout.
I believe that the C++ Standard does not offer a way of checking the standard input without blocking. Since you are willing to use platform specific functions, 'kbhit()' might suit your needs but it has been deprecated in Windows. An alternative is offered, _kbhit(). Of course this is not portable to other platforms.
This is the link to MSDN: _kbhit
What you could do is using futures to allow the user to input something with a time limit. You can then insert this code into your main loop
#include <iostream> // std::cout
#include <future> // std::async, std::future
#include <chrono> // std::chrono::milliseconds
#include <string>
using namespace std;
bool myAsyncGetline(string & result)
{
std::cout<<"Enter something within the time limit"<<endl;
getline(cin,result);
return true;
}
int main()
{
// call function asynchronously:
string res;
std::future<bool> fut = std::async (myAsyncGetline,res);
std::chrono::seconds span (20);
if (fut.wait_for(span)==std::future_status::timeout)
std::cout << "Too Late!";
else
cout<<"You entered "<<res<<" "<< endl;
return 0;
}
This is available in VS2012 so you should be able to reproduce it.
The output is "Tool Late!" if getline is still working after the timeout (20s), otherwise it outputs the result.
I think that it is simpler than messing around with killing thread as the function stop by itself if the time limit is hit.
Tell me if you need help integrating it into your existing code I can assist.
There is another process continuously creating files that need processing by this code.
This code constantly scans the file-system for new files that need processing by comparing the contents of the file-system against a sqlite database that contains the processing results - one record for each file. This process is running at nice -n 19 so as not to interfere with the creation of new files by the other process.
It all works perfectly for a large number (>1k) of files, but then blows up with BUG: scheduling while atomic.
According to this
"Scheduling while atomic" indicates that you've tried to sleep
somewhere that you shouldn't
But the only sleep in the code is like this
void doFiles(void) {
for (...) { // for each file in the file-system
... // check database - do processing if needed
}
sleep(1);
}
int main(int argc, char *argv[], char *envp[]) {
while (true) doFiles();
return -1;
}
The code will hit this sleep after it has checked every file in the file-system against the database. The process needs to be repeated since new files will be added from time to time. There is no multi-threading in this code. Are there other possible causes for "BUG: scheduling while atomic" besides a misplaced sleep?
Edit: additional error output:
note: mirlin[1083] exited with preempt_count 1
BUG: scheduling while atomic: mirlin/1083/0x40000002
Modules linked in: g_cdc_ms musb_hdrc nop_usb_xceiv irqk edmak dm365mmap cmemk
Backtrace:
[<c002a5a0>] (dump_backtrace+0x0/0x110) from [<c028e56c>] (dump_stack+0x18/0x1c)
r6:c1099460 r5:c04ea000 r4:00000000 r3:20000013
[<c028e554>] (dump_stack+0x0/0x1c) from [<c00337b8>] (__schedule_bug+0x58/0x64)
[<c0033760>] (__schedule_bug+0x0/0x64) from [<c028e864>] (schedule+0x84/0x378)
r4:c10992c0 r3:00000000
[<c028e7e0>] (schedule+0x0/0x378) from [<c0033a80>] (__cond_resched+0x28/0x38)
[<c0033a58>] (__cond_resched+0x0/0x38) from [<c028ec6c>] (_cond_resched+0x34/0x44)
r4:00013000 r3:00000001
[<c028ec38>] (_cond_resched+0x0/0x44) from [<c0082f64>] (unmap_vmas+0x570/0x620)
[<c00829f4>] (unmap_vmas+0x0/0x620) from [<c0085c10>] (exit_mmap+0xc0/0x1ec)
[<c0085b50>] (exit_mmap+0x0/0x1ec) from [<c0037610>] (mmput+0x40/0xfc)
r9:00000001 r8:80000005 r6:c04ea000 r5:00000000 r4:c0427300
[<c00375d0>] (mmput+0x0/0xfc) from [<c003b5e4>] (exit_mm+0x150/0x158)
r5:c10992c0 r4:c0427300
[<c003b494>] (exit_mm+0x0/0x158) from [<c003cd44>] (do_exit+0x198/0x67c)
r7:c03120d1 r6:c10992c0 r5:0000000b r4:c10992c0
...
As others have said, you can sleep() anytime you want to in user code.
Looks like a problem with a driver on your platform. The driver may not actually call sleep() or schedule(), but often it will make a call of an kernel function which will, in turn, call one of these.
This also looks like it is using memory mapped file I/O on an embedded TI ARM processor.
This error was caused by a bad build.
A clean build by itself did not help.
A fresh checkout and build was required to resolve this issue.
I have an application which runs on a controlling hardware connected with different sensors. On loading the application, it checks the individual sensors one by one to see whether there is proper communication with the sensor according to predefined protocol or not.
Now, I have implemented the code for checking the individual sensor communication as a singleton thread and following is the run function, it used select system call and pipe for interprocess communication to signal the end of thread.
void SensorClass::run()
{
mFdWind=mPort->GetFileDescriptor();
fd_set readfs;
int max_fd = (mFdWind > gPipeFdWind[0] ? mFdWind : gPipeFdWind[0]) + 1;
int res;
mFrameCorrect=false;
qDebug("BEFORE WHILE");
while(true)
{
qDebug("\n IN WHILE LOOP");
usleep(50);
FD_ZERO(&readfs);
FD_SET(mFdWind,&readfs);
FD_SET(gPipeFdWind[0],&readfs);
res=select(max_fd,&readfs,NULL,NULL,NULL);
if(res < 0)
perror("Select Failed");
else if(res == 0)
puts("TIMEOUT");
else
{
if(FD_ISSET(mFdWind,&readfs))
{
puts("*************** RECEIVED DATA ****************");
mFrameCorrect=false;
FlushBuf();
//int n=mPort->ReadPort(mBuf,100);
int n=mPort->ReadPort(mBuf,100);
if(n>0)
{
Count++;
QString str((const char*)mBuf);
//qDebug("\n %s",qPrintable(str));
//See if the Header of the frame is valid
if(IsHeaderValid(str))
{
if( (!IsCommaCountOk(str)) || (!IsChecksumOk(str,mBuf)) || (!CalculateCommaIndexes(str)) )
{
qDebug("\n not ok");
mFrameCorrect=false;
} //if frame is incorrect
else
{
qDebug("\n OK");
mFrameCorrect=true;
}//if frame is correct(checksum etc are ok)
}//else if header is ok
}//if n > 0
}//if data received FD_ISSET
if(FD_ISSET(gPipeFdWind[0],&readfs))
break;
}//end nested else res not <= 0
}//infinite loop
}
The above thread is run started from the main GUI thread. This runs fine. The problem is I have given an option to the user to retest the subsystem at will. For this I delete the singleton instance using
delete SensorClass::instance();
and then restart the singleton using
SensorClass::instace()->start();
The problem is this time the control comes out of while loop in run() function immedeately upon entering the while loop, my guess is the pipe read has again read from the write pipe which was written to the last time. I have tried to use the fflush() to clear out the I/O but no luck.
My question is
Am I thinking on the right track?
If yes then how do we clear out the pipes?
If not can anyone suggest why is the selective retest not working?
Thanks in advance..
fflush clears the output buffer. If you want to clear the input buffer, you're going to need to read the data or seek to the end.
I'm not convinced the "Singleton" pattern is appropriate. There are other ways of ensuring at most one instance for each piece of hardware. What if you later want multiple threads, each working with a different sensor?
Let's assume that you're creating this thread by inheriting from QThread (which you don't specify). From the documentation of QThread::~QThread ():
Note that deleting a QThread object will not stop the execution of the thread it represents. Deleting a running QThread (i.e. isFinished() returns false) will probably result in a program crash.
So the statement delete SensorClass::instance(); is probably a really, really bad idea. In particular, it's going to be tough making any sense of this program's behavior given this flaw. Before continuing, you might want to find a way to remove the instance and ensure that the thread goes away, too.
Another problem comes to mind. When you run delete SensorClass::instance(), you get rid of some object (on the heap, one hopes). Who tells the singleton holder that its object is gone? E.g. so that the next call to SensorClass::instance() knows it needs to allocate another instance? Is this handled properly in SensorClass::~SensorClass?
Suppose that's not a problem. That likely means that the pointer to the instance is held in a global variable (or, e.g. a class level static member). It probably doesn't matter for this situation, but is access to that member properly synchronized? I.e. is there a mutex that's locked for each access to it?
You really don't want to run your initialization in thread. That is issue number one that dramatically complicates your problem and which is the kind of thing for some reason no one points out.
Just make the initialization its own function, then have a guard variable and lock, and have everything that uses it separately initialize it when they start up.
So you're signaling by writing something to the pipe, and the pipe is only created once - i.e. reused in the later threads?
Read the signaling away from the pipe. Assuming you signal by writing a single byte, then instead of just breaking out, you'd do something like (NB, no error checking etc below):
if(FD_ISSET(gPipeFdWind[0],&readfs)) {
char c;
read(gPipeFdWind[0], &c, 1);
break;
}
There are also Qt classes for handling socket I/O, e.g. QTcpSocket, which would make the code not only cleaner, also more cross-platform. Or at least QSocketNotifier to abstract the select away.