emil-e/rapidcheck

Crash on dereferencing generator when multiple threads are used

igchor opened this issue · 4 comments

Hi!

I encountered a problem with the following code:

#include <cassert>
#include <rapidcheck.h>
#include <thread>
#include <vector>

int main(int argc, char *argv[])
{
	return rc::check("generator", [&] {
		std::vector<std::thread> threads;
		for (int i = 0; i < 2; i++) {
			threads.emplace_back([&] {
				auto ret = *rc::gen::inRange<unsigned>(0, 10);
				assert(ret <= 10);
			});
		}
		for (auto &t : threads)
			t.join();
	});
}

Below is output from the program:

Using configuration: seed=8356093754809374738

- generator
terminate called after throwing an instance of 'std::runtime_error'
  what():  operator* is not allowed in this context

It looks like it's not possible to use generators from multiple thread. Is this expected? Is there some workaround for this?

I compiled my code using G++ 9.3.0-17ubuntu1~20.04 like this:
g++ test.cpp /usr/lib/x86_64-linux-gnu/librapidcheck.a -lpthread

Correct, the dereferencing operator is not thread safe. Support for running multiple tests in separate isolated threads could be implemented using thread locals. However, the use case you're describing is inherently impossible - the order of execution is non-deterministic (or rather, controlled by the OS scheduler) and thus the test is not deterministic. Tests must be deterministic to work with RapidCheck.

Thanks! I have one more, follow-up question. Let's say I have a multithreaded test that does not use generators from multiple threads (all the data is precalculated in the main thread). The test is nondeterministic.

Is it possible to use RapidCheck for such test? I would imagine that shrinking might be problematic in such a case - what if I disabled it?

Yes, shrinking would absolutely not work. It's possible you could get some value out of RapidCheck even with shrinking disabled but it's definitely an unsupported use case. I would strongly recommend that you separate the concurrency model from the business logic somehow, in order to test the business logic separately with RapidCheck. That is, if possible.

Got it, thanks for the quick reply!