-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Thread safety of r_sink_mt()
#22
Comments
There may well a way, as there is upstream, but I have not had time to dig -- maybe you can. I assume you are aware of the limitations that R has when it comes to multithreaded code: you simply cannot call back from any portion. The vignette of package RcppParallel describes this well. But conceivably, with data in C++ datatype that do not share with R this may work. You may want to try file-based or other loggers as |
Thanks!
This |
Oh, that is nice. I should document that (and give you credit). |
Very nice:
Any idea why I get Complete version of your two files amalgamated and slightly modified to be callable multiple times below. // [[Rcpp::depends(RcppSpdlog)]]
// [[Rcpp::depends(RcppThread)]]
// [[Rcpp::plugins(openmp)]]
#include <RcppThread.h>
#include <RcppSpdlog>
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_sinks.h>
#include <omp.h>
namespace mynamespace {
namespace sinks {
template<typename Mutex>
class rcppthread_sink : public spdlog::sinks::r_sink<Mutex> {
protected:
void sink_it_(const spdlog::details::log_msg& msg) override {
spdlog::memory_buf_t formatted;
spdlog::sinks::base_sink<Mutex>::formatter_->format(msg, formatted);
#ifdef SPDLOG_USE_STD_FORMAT
RcppThread::Rcout << formatted;
#else
RcppThread::Rcout << fmt::to_string(formatted);
#endif
}
void flush_() override {
RcppThread::Rcout << std::flush;
}
};
using rcppthread_sink_mt = rcppthread_sink<std::mutex>;
} // namespace sinks
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<spdlog::logger> rcppthread_sink_mt(const std::string &logger_name) {
return Factory::template create<sinks::rcppthread_sink_mt>(logger_name);
}
} // namespace mynamespace
// [[Rcpp::export]]
void omp_spdlog() {
const int size = 8;
std::string logname = "console";
auto console = spdlog::get(logname);
if (console == nullptr) console = mynamespace::rcppthread_sink_mt(logname);
spdlog::set_default_logger(console);
console->set_pattern("[%n] [thread %t] %v");
console->info("Number of threads: {}", omp_get_max_threads());
#pragma omp parallel for
for (int i = 0; i < size; ++i) {
int thread_id = omp_get_thread_num();
console->info("Thread {} processing index {}", thread_id, i);
}
}
/*** R
omp_spdlog()
*/
|
I committed this in d3d8ef7, please let me know if you think it needs another update. Thanks for the suggestion! |
Thanks! About |
Yes -- I was in a rush earlier and didn't look. I think it copies a (bad !!) setup I once had added in It's only an issue for |
Another solution is possible - Here's how to use it: #include <Rcpp.h>
#include <RcppThread.h> // using only #include <RcppThread/Rcout.hpp> is okay
#define Rcout RcppThreadRcout
namespace Rcpp {
static RcppThread::RPrinter RcppThreadRcout = RcppThread::RPrinter();
} // namespace Rcpp
#include <RcppSpdlog> This is simpler than defining a derived class (but I haven't checked if this affects other
|
Sure. But if I may, and with all the appreciattion for the earlier help: If you want to make real improvements, learn to do a proper PR, and thoroughly test it before submitting. I cannot spend all my times combining partial file snippets you put up here just because that is your current focus. Either way we have a remaining dependency on RcppThreads. The best would probably be to (one day) talk to Thomas and see if he wants to 'donate' the monitor class used and the Rcout/Rcerr reimplementations to Rcpp. Then we'd be zero-depends there. |
I initially assumed that
r_sink_mt
would be thread-safe because it uses*_mt
. However, when I tried using it with OpenMP loop, it appears to be non-thread-safe.Upon reviewing its code, I noticed that it uses
Rcpp::Rcout
which is inherently not thread-safe.rcppspdlog/inst/include/rcpp_sink.h
Lines 38 to 42 in 84fe635
Others using stdout, such as
stdout_logger_mt()
, work as expected in the same OpenMp loop. Is there a way with this package to implement thread-safe logger without relying on stdout?Here is my minimal example.
If I use
spdlog::r_sink_mt("console")
instead, I get error in the R console sayingEnvironment:
The text was updated successfully, but these errors were encountered: