2013-08-12 21:10:21 +00:00
|
|
|
/*
|
|
|
|
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
|
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
|
|
|
*/
|
2013-08-12 21:50:48 +00:00
|
|
|
#include <cstdlib>
|
2013-08-12 21:10:21 +00:00
|
|
|
#include <thread>
|
|
|
|
#include <iostream>
|
|
|
|
#include <mutex>
|
|
|
|
#include <vector>
|
2013-11-18 22:03:18 +00:00
|
|
|
#include <atomic>
|
|
|
|
#include "util/debug.h"
|
2013-11-12 04:00:21 +00:00
|
|
|
#include "util/shared_mutex.h"
|
2013-11-22 19:32:09 +00:00
|
|
|
#include "util/interrupt.h"
|
2013-11-18 22:03:18 +00:00
|
|
|
using namespace lean;
|
2013-08-12 21:10:21 +00:00
|
|
|
|
2013-09-10 20:50:35 +00:00
|
|
|
void foo() {
|
2013-08-12 21:10:21 +00:00
|
|
|
static thread_local std::vector<int> v(1024);
|
|
|
|
if (v.size() != 1024) {
|
|
|
|
std::cerr << "Error\n";
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tst1() {
|
|
|
|
unsigned n = 5;
|
|
|
|
for (unsigned i = 0; i < n; i++) {
|
|
|
|
std::thread t([](){ foo(); });
|
|
|
|
t.join();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-12 04:00:21 +00:00
|
|
|
static void tst2() {
|
|
|
|
unsigned N = 10;
|
|
|
|
unsigned n = 1;
|
|
|
|
lean::shared_mutex mut;
|
|
|
|
std::vector<std::thread> threads;
|
|
|
|
for (unsigned i = 0; i < N; i++) {
|
|
|
|
threads.emplace_back([&]() {
|
|
|
|
unsigned sum = 0;
|
|
|
|
{
|
|
|
|
lean::shared_lock lock(mut);
|
|
|
|
for (unsigned i = 0; i < 1000000; i++)
|
|
|
|
sum += n;
|
|
|
|
}
|
|
|
|
{
|
|
|
|
lean::unique_lock lock(mut);
|
|
|
|
std::cout << sum << "\n";
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
for (unsigned i = 0; i < N; i++)
|
|
|
|
threads[i].join();
|
|
|
|
}
|
|
|
|
|
2013-12-04 18:27:18 +00:00
|
|
|
#if !defined(__APPLE__) && !defined(LEAN_THREAD_UNSAFE)
|
2013-11-18 22:03:18 +00:00
|
|
|
static void tst3() {
|
|
|
|
shared_mutex mutex;
|
|
|
|
std::atomic<bool> t2_started(false);
|
|
|
|
std::atomic<bool> t2_done(false);
|
|
|
|
std::chrono::milliseconds small_delay(10);
|
|
|
|
|
|
|
|
std::thread t1([&]() {
|
|
|
|
while (!t2_started) {
|
|
|
|
std::this_thread::sleep_for(small_delay);
|
|
|
|
}
|
|
|
|
while (!mutex.try_lock()) {
|
|
|
|
std::this_thread::sleep_for(small_delay);
|
|
|
|
}
|
2013-11-20 19:28:19 +00:00
|
|
|
// test recursive try_lock
|
|
|
|
lean_verify(mutex.try_lock());
|
|
|
|
mutex.unlock();
|
2013-11-18 22:03:18 +00:00
|
|
|
// we can only succeed getting the lock if t2 is done
|
|
|
|
lean_assert(t2_done);
|
|
|
|
mutex.unlock();
|
|
|
|
});
|
|
|
|
|
|
|
|
std::thread t2([&]() {
|
|
|
|
{
|
|
|
|
unique_lock lock(mutex);
|
|
|
|
t2_started = true;
|
|
|
|
std::this_thread::sleep_for(small_delay);
|
|
|
|
}
|
|
|
|
t2_done = true;
|
|
|
|
});
|
|
|
|
|
|
|
|
t1.join();
|
|
|
|
t2.join();
|
|
|
|
lean_assert(t2_done);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tst4() {
|
|
|
|
shared_mutex mutex;
|
|
|
|
std::atomic<bool> t2_started(false);
|
|
|
|
std::atomic<bool> t2_done(false);
|
|
|
|
std::chrono::milliseconds small_delay(10);
|
|
|
|
|
|
|
|
std::thread t1([&]() {
|
|
|
|
while (!t2_started) {
|
|
|
|
std::this_thread::sleep_for(small_delay);
|
|
|
|
}
|
|
|
|
while (!mutex.try_lock_shared()) {
|
|
|
|
std::this_thread::sleep_for(small_delay);
|
|
|
|
}
|
2013-11-20 19:28:19 +00:00
|
|
|
// test recursive try_lock_shared
|
|
|
|
lean_verify(mutex.try_lock_shared());
|
|
|
|
mutex.unlock_shared();
|
2013-11-18 22:03:18 +00:00
|
|
|
// we can only succeed getting the lock if t2 is done
|
|
|
|
lean_assert(t2_done);
|
|
|
|
mutex.unlock_shared();
|
|
|
|
});
|
|
|
|
|
|
|
|
std::thread t2([&]() {
|
|
|
|
{
|
|
|
|
unique_lock lock(mutex);
|
|
|
|
t2_started = true;
|
|
|
|
std::this_thread::sleep_for(small_delay);
|
|
|
|
}
|
|
|
|
t2_done = true;
|
|
|
|
});
|
|
|
|
|
|
|
|
t1.join();
|
|
|
|
t2.join();
|
|
|
|
lean_assert(t2_done);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tst5() {
|
|
|
|
shared_mutex mutex;
|
|
|
|
std::atomic<bool> t2_started(false);
|
|
|
|
std::atomic<bool> t1_done(false);
|
|
|
|
std::chrono::milliseconds small_delay(10);
|
|
|
|
|
|
|
|
std::thread t1([&]() {
|
|
|
|
while (!t2_started) {
|
|
|
|
std::this_thread::sleep_for(small_delay);
|
|
|
|
}
|
|
|
|
lean_verify(mutex.try_lock_shared()); // t2 is also using a shared lock
|
|
|
|
std::this_thread::sleep_for(small_delay);
|
|
|
|
lean_verify(mutex.try_lock_shared());
|
|
|
|
std::this_thread::sleep_for(small_delay);
|
|
|
|
t1_done = true;
|
|
|
|
mutex.unlock_shared();
|
|
|
|
std::this_thread::sleep_for(small_delay);
|
|
|
|
mutex.unlock_shared();
|
|
|
|
});
|
|
|
|
|
|
|
|
std::thread t2([&]() {
|
|
|
|
{
|
|
|
|
shared_lock lock(mutex);
|
|
|
|
t2_started = true;
|
|
|
|
while (!t1_done) {
|
|
|
|
std::this_thread::sleep_for(small_delay);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
t1.join();
|
|
|
|
t2.join();
|
|
|
|
}
|
2013-11-22 19:32:09 +00:00
|
|
|
|
|
|
|
static void tst6() {
|
|
|
|
interruptible_thread t1([]() {
|
|
|
|
try {
|
|
|
|
// Remark: std::this_thread::sleep_for does not check whether the thread has been interrupted or not.
|
|
|
|
// std::this_thread::sleep_for(std::chrono::milliseconds(1000000));
|
|
|
|
sleep_for(1000000);
|
|
|
|
} catch (interrupted &) {
|
|
|
|
std::cout << "interrupted...\n";
|
|
|
|
}
|
|
|
|
});
|
|
|
|
sleep_for(20);
|
|
|
|
t1.request_interrupt();
|
|
|
|
t1.join();
|
|
|
|
}
|
2013-11-18 22:03:18 +00:00
|
|
|
#else
|
|
|
|
static void tst3() {}
|
|
|
|
static void tst4() {}
|
|
|
|
static void tst5() {}
|
2013-11-22 19:32:09 +00:00
|
|
|
static void tst6() {}
|
2013-11-18 22:03:18 +00:00
|
|
|
#endif
|
|
|
|
|
2013-08-12 21:10:21 +00:00
|
|
|
int main() {
|
2013-12-01 20:42:32 +00:00
|
|
|
save_stack_info();
|
2013-08-12 21:10:21 +00:00
|
|
|
tst1();
|
2013-11-18 22:03:18 +00:00
|
|
|
tst2();
|
|
|
|
tst3();
|
|
|
|
tst4();
|
|
|
|
tst5();
|
2013-11-22 19:32:09 +00:00
|
|
|
tst6();
|
2013-11-18 22:03:18 +00:00
|
|
|
return has_violations() ? 1 : 0;
|
2013-08-12 21:10:21 +00:00
|
|
|
}
|