Skip to content

Commit d1c6dbe

Browse files
Ivan Karachunbader
authored andcommitted
[SYCL] Removed mutex leading to deadlock (#889)
The deadlock appeared under following circumstances: 1) thread1: adds nodes to the graph for host accessor A1 to the buffer B; 2) thread2: adds nodes to the graph for host accessor A2 to the buffer B; 3) thread2: waits for host accessor A2 nodes to complete; 4) thread1: waits for host accessor A1 nodes to complete. On step 3 thread2 locks a mutex in `Scheduler::waitForEvent` and waits for destruction of host accessor A1. Actions on step 4 cannot be completed because thread1 waits for the mutex to be unlocked. Signed-off-by: Ivan Karachun <[email protected]>
1 parent 5f80ce6 commit d1c6dbe

File tree

5 files changed

+86
-1
lines changed

5 files changed

+86
-1
lines changed

sycl/source/detail/scheduler/scheduler.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ std::vector<EventImplPtr> Scheduler::getWaitList(EventImplPtr Event) {
109109
}
110110

111111
void Scheduler::waitForEvent(EventImplPtr Event) {
112-
std::lock_guard<std::mutex> lock(MGraphLock);
113112
GraphProcessor::waitForEvent(std::move(Event));
114113
}
115114

sycl/unittests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,4 @@ endfunction()
3434

3535
add_subdirectory(pi)
3636
add_subdirectory(misc)
37+
add_subdirectory(thread_safety)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
add_sycl_unittest(ThreadSafetyTests
2+
HostAccessorDeadLock.cpp
3+
)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//==----- HostAccessorDeadLock.cpp --- Thread Safety unit tests ------------==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "ThreadUtils.h"
10+
#include <CL/sycl.hpp>
11+
#include <gtest/gtest.h>
12+
#include <mutex>
13+
#include <vector>
14+
15+
namespace {
16+
constexpr auto sycl_read_write = cl::sycl::access::mode::read_write;
17+
18+
TEST(HostAccessorDeadLockTest, CheckThreadOrder) {
19+
constexpr std::size_t size = 1;
20+
constexpr std::size_t threadCount = 4, launchCount = 5;
21+
22+
{
23+
cl::sycl::buffer<std::size_t, 1> buffer(size);
24+
25+
auto testLambda = [&](std::size_t threadId) {
26+
auto acc = buffer.get_access<sycl_read_write>();
27+
};
28+
29+
for (std::size_t k = 0; k < launchCount; ++k) {
30+
ThreadPool MPool(threadCount, testLambda);
31+
}
32+
}
33+
}
34+
} // namespace
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include <thread>
2+
#include <vector>
3+
4+
class ThreadPool {
5+
public:
6+
ThreadPool() = delete;
7+
ThreadPool(ThreadPool &) = delete;
8+
9+
template <typename Func>
10+
ThreadPool(std::size_t N, Func func) {
11+
for (std::size_t i = 0; i < N; ++i) {
12+
enqueue(func, i);
13+
}
14+
}
15+
16+
template <typename Func, typename... Funcs>
17+
ThreadPool(Func &&func, Funcs &&... funcs) {
18+
constexpr int N = sizeof...(funcs);
19+
enqueue(std::forward<Func>(func), N);
20+
enqueueHelper<N>(std::forward<Funcs>(funcs)...);
21+
}
22+
23+
~ThreadPool() { wait(); }
24+
25+
private:
26+
template <int N, typename Func, typename... Funcs>
27+
void enqueueHelper(Func &&func, Funcs &&... funcs) {
28+
enqueue(std::forward<Func>(func), N - 1);
29+
enqueueHelper<N - 1>(std::forward<Funcs>(funcs)...);
30+
}
31+
32+
template <int N>
33+
void enqueueHelper() {}
34+
35+
template <typename Func, typename... Args>
36+
void enqueue(Func &&func, Args &&... args) {
37+
MThreadPool.emplace_back(std::forward<Func>(func),
38+
std::forward<Args>(args)...);
39+
}
40+
41+
void wait() {
42+
for (auto &t : MThreadPool) {
43+
t.join();
44+
}
45+
}
46+
47+
std::vector<std::thread> MThreadPool;
48+
};

0 commit comments

Comments
 (0)