Original post is under the spoiler below, but there is a mush better explanation in the second post.
As clearly stated in documentation:
How to reproduce: have "About Rainmeter" window open and launch a background thread spamming either one of these commands, then unload skin with this thread.
When "About Rainmeter" window is not open, everything works as expected. It must be open in the moment when you unload the skin.
Below is a code of a simplest possible plugin, that reproduces this bug. With a new log message every 1.0 ms it is pretty consistent: rainmeter hang every time I tested.
In rainmeter log you can see that plugin flawlessly prints messages until it stopped.
Finalize function calls thread.join(), which ensures that thread finishes before plugin measure is destroyed, so condition "make sure to check if the skin is still running" holds.
RmExecute acts absolutely identical, except it requires different args to cause this issue.
Tested on latest available version: 4.4.0.3404 beta (64-bit), commit hash a0c762cf
Windows version: Windows 10 Enterprise 2016 LTSB 1607 64-bit (build 14393) - English (1033)
However, when called from another thread, both RmExecute and RmLog can cause rainmeter main thread to hang. Though, I only tested RmExecute using RmExecute("[!log message]"), so maybe it's only a logging bug.Most of the API functions should not be called in separate threads as they are not thread-safe. RmExecute and RmLog will be the exceptions, but make sure to check if the skin is still running.
How to reproduce: have "About Rainmeter" window open and launch a background thread spamming either one of these commands, then unload skin with this thread.
When "About Rainmeter" window is not open, everything works as expected. It must be open in the moment when you unload the skin.
Below is a code of a simplest possible plugin, that reproduces this bug. With a new log message every 1.0 ms it is pretty consistent: rainmeter hang every time I tested.
In rainmeter log you can see that plugin flawlessly prints messages until it stopped.
Finalize function calls thread.join(), which ensures that thread finishes before plugin measure is destroyed, so condition "make sure to check if the skin is still running" holds.
RmExecute acts absolutely identical, except it requires different args to cause this issue.
Code: Select all
#include <atomic>
#include <thread>
#include "RainmeterAPI.h"
struct Test {
void* rm = nullptr;
std::thread thread;
std::atomic<bool> stopRequest{ false };
void start(void* _rm) {
rm = _rm;
thread = std::thread{
[&]() {
threadFunction();
}
};
}
void threadFunction() {
using namespace std::chrono_literals;
while(true) {
if (stopRequest.load()) {
break;
}
RmLog(rm, 0, L"hello from another thread");
std::this_thread::sleep_for(1.0ms);
}
}
};
PLUGIN_EXPORT void Initialize(void** data, void* rm) {
auto test = new Test {};
test->start(rm);
*data = test;
}
PLUGIN_EXPORT void Finalize(void* data) {
auto test = static_cast<Test*>(data);
test->stopRequest.exchange(true);
test->thread.join();
delete test;
}
Windows version: Windows 10 Enterprise 2016 LTSB 1607 64-bit (build 14393) - English (1033)