3

I want to create a multithread logger in c++ which can be called from c code as well.

This is in my source.cpp file:

#include <cstdlib>
#include <iostream>
#include <thread>
#include "source.h"
using namespace std;

#ifdef __cplusplus
extern "C" {
#endif
class thread_obj {
public:
    void operator()(float* x)
    {
        printf("value: %d", x);
    }
};

void log(float value)
{
    thread th1(thread_obj(), value);
    th1.join();
}

#ifdef __cplusplus
}
#endif

And this is in source.h:

#ifdef __cplusplus
extern "C" {
#endif
    void log(float value);
#ifdef __cplusplus
}
#endif

And now I want to use this from a C file like: log(myFloatValue);, of course with included header file.

But I got some strange errors, like:

Error   C2672   'invoke': no matching overloaded function found myproj C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.27.29110\include\thread   43  
Error   C2893   Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Ty1 &&,_Types2 &&...) noexcept(<expr>)'  myproj C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.27.29110\include\thread   39  
Error   C2780   'unknown-type std::invoke(_Callable &&) noexcept(<expr>)': expects 1 arguments - 2 provided hackatlon_0_0_1 C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.27.29110\include\thread  39  

My question is, how can I do this, or how can I solve these errors?

alma korte
  • 135
  • 7
  • Which language, C or C++? Your answers may vary depending on the language. Adjust your language tags appropriately. – Thomas Matthews Oct 15 '21 at 18:31
  • @ThomasMatthews This is a C++code what I want to call from C code. – alma korte Oct 15 '21 at 18:32
  • 2
    If I remember correctly I think you should not do extern "C" on the class part. The C++ bit should be completely hidden to "C". So void log(float value) should forward to an internal class, but that class should not be exported – Pepijn Kramer Oct 15 '21 at 18:32
  • @PepijnKramer I've created this based on this stack overflow answer: https://stackoverflow.com/a/29192858 – alma korte Oct 15 '21 at 18:36
  • 3
    As for the multithread part, you probably want a queue of messages that will be filled by log calls (producer) and then do the actual logging from the log thread (consumer). If you spawn a thread like you do now and then join it it is just a very expensive synchronous call. – Pepijn Kramer Oct 15 '21 at 18:36
  • That example doesn't export the C++ class either. It will lazily create an instance of AAA in the implementation of the "C" call but doesn't export the class in the header file. – Pepijn Kramer Oct 15 '21 at 18:38
  • @PepijnKramer yep, something like that... – alma korte Oct 15 '21 at 18:38
  • 1
    @PepijnKramer right, not to mention, you should take enough memory resources into account for buffering. – πάντα ῥεῖ Oct 15 '21 at 18:39
  • Did you think about using some ready library or is it just a personal training? There are many great solutions. [glog](http://code.google.com/p/google-glog/) for example. – Marek R Oct 15 '21 at 18:39
  • @almakorte well, the problem I see with your question is, that the title asks for a very broad problem to solve, while the point you're actually stuck with is more or less a trivial syntax error. You should probably focus more on the latter one, and provide a [mcve] as required here. – πάντα ῥεῖ Oct 15 '21 at 18:41
  • @MarekR I want to use it and understand it, both, but I never used libs like glog – alma korte Oct 15 '21 at 18:44
  • @πάνταῥεῖ ok, than what is that trivial error? :) I've posted here the whole code.... – alma korte Oct 15 '21 at 18:46
  • @PepijnKramer *As for the multithread part, you probably want a queue of messages that will be filled by log calls (producer) and then do the actual logging from the log thread (consumer).* That's the hard way to do it. On POSIX systems, just open the file with `O_APPEND`, format the entire log message into a single buffer, and then `write()` the buffer to the file. No queue and no threading necessary. On Windows, [this answer](https://stackoverflow.com/a/18933306/4756299) states using `CreateFile()` with `FILE_APPEND_DATA` and then calling `WriteFile()` will do the same. – Andrew Henle Oct 15 '21 at 19:16
  • @AndrewHenle 'just open the file' takes much, much longer than allocating/depooling a buffer, loading it with log data and queueing its pointer off. That is just one reason why a dev might prefer to thread off the file write. There are plenty others. – Martin James Oct 16 '21 at 01:23
  • @MartinJames Open the file when logging is initialized and the leave the file open. That should have been obvious. – Andrew Henle Oct 16 '21 at 01:29
  • ..or did you mean 'keep the file open'.. if so, fine, yes, just write to the file. Of course, your logging caller will need to tolerate occasional long delays from directory updates, latencies with networked log files etc. – Martin James Oct 16 '21 at 01:31
  • @MartinJames Why are you doing synchronous writes that don't use the page cache for a log file? – Andrew Henle Oct 16 '21 at 01:34
  • ..and vastly complicate any requirements like 'open a new log file every hour/10MB/whenever requested by human interface. – Martin James Oct 16 '21 at 01:34
  • @MartinJames `rename( logFileName, newLogFileName); int newFd = open( logFileName, O_CREAT | O_APPEND ... ); dup2( newFd, logFileFd );` Transparent rotation of a log file, off the top of my head in about 2 minutes. Oh yeah, I even looked up [proof that `dup2()` is atomic](https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_09_07). – Andrew Henle Oct 16 '21 at 01:37
  • ...any synchronous write is somewhat hazardous, which is why it is safer threaded off to some low-priority logger thread that doesn't care if it gets stuck for 30 seconds on some network funny. – Martin James Oct 16 '21 at 01:37
  • 'rename....', OK, what is going to call that? – Martin James Oct 16 '21 at 01:39
  • Any time you need to rotate your log file. Like a `SIGHUP` signal handler to rotate the log file whenever the process gets a `SIGHUP` signal. All of those calls, besides being atomic, are also all async-signal-safe. – Andrew Henle Oct 16 '21 at 01:41
  • @AndrewHenle Yeah I know using the multithreaded approach ( produced/consumer method) is the hard way, but Alma asked for a multithreaded approach :) I got the best result with circular logs memory mapped files and reader/writer locks (for realtime observation of the logs) that immediately takes care of the buffer size. And they're pretty reliable in case of crashes (memory file is flushed). Only losses are sometimes at unexpected hardware shutdowns and they're usually not much – Pepijn Kramer Oct 16 '21 at 03:45

1 Answers1

1

There are multiple problems with your code:

  1. argument for operator() should be float x NOT float* since this is what you are passing to thread
  2. your log function conflicts with standard math log. Either change function name or put it into different namespace
  3. printf using format specifier "%d". It should be "%f" since input is float
  4. You don't need to put extern "C" for classes. You are avoiding name mangling only for log function which need to be called from c file.
Shailesh
  • 328
  • 5
  • 15