Hi, I'm getting a hang/deadlock when when initializing an Intel OpenCL context from a TBB thread on Linux. On Windows, it's fine. Please try the attached source code.
// ocl_test.cpp // // Compile with: g++ -std=c++14 -I/path/to/opencl/include -I/path/to/tbb/include -lOpenCL -ltbb -lpthread -L. ocl_test.cpp -o ocl_test // // cl.hpp used from: https://www.khronos.org/registry/OpenCL/api/2.1/cl.hpp // // Run with: // $ cd /path/to/parent/dir/libintelocl.so // $ env LD_LIBRARY_PATH=. LD_PRELOAD=libintelocl.so ./ocl_test // // This hangs on Linux under various Intel processors but not Windows // #include <iostream> #include <future> #include <atomic> #include <vector> #define __CL_ENABLE_EXCEPTIONS #define CL_TARGET_OPENCL_VERSION 120 #include "cl.hpp" #ifdef _WIN32 #ifdef _DEBUG #pragma comment(lib, "OpenCL_d") #pragma comment(lib, "tbb_debug") #else #pragma comment(lib, "OpenCL") #pragma comment(lib, "tbb") #endif #endif //#define TEST_STDTHREAD #define TEST_TBB #ifdef TEST_TBB #include <tbb/tbb.h> template <typename F> class LambdaTask : public tbb::task { public: LambdaTask(const F& f) : myF(f) { } private: tbb::task* execute() override { if (myF()) { return new(tbb::task::allocate_continuation()) LambdaTask(myF); } return nullptr; } F myF; }; template <typename F> static void EnqueueLambda(const F& f) { tbb::task::enqueue( *new(tbb::task::allocate_root()) LambdaTask<F>(f) ); } template <typename F> static void SpawnAndWaitLambda(const F& f) { tbb::task::spawn_root_and_wait( *new(tbb::task::allocate_root()) LambdaTask<F>(f) ); } #endif int main() { std::vector<cl::Platform> platforms; cl::Platform::get(&platforms); if (platforms.empty()) { std::cout << "No platforms found.\n"; return 1; } for (const cl::Platform &platform : platforms) { std::cout << "Available platform: "<< platform.getInfo<CL_PLATFORM_NAME>() << "\n"; } cl::Platform platform = platforms[0]; std::cout << "Using platform: "<< platform.getInfo<CL_PLATFORM_NAME>() << "\n"; std::vector<cl::Device> devices; platform.getDevices(CL_DEVICE_TYPE_ALL, &devices); if (devices.empty()) { std::cout << "No devices found.\n"; return 1; } cl::Device device = devices[0]; std::cout << "Using device: "<< device.getInfo<CL_DEVICE_NAME>() << "\n"; auto create_context = [&]() { std::cout << "Attempting to create context"<< std::endl; cl::Context context({device}); std::cout << "Created context"<< std::endl; }; #if defined(TEST_STDTHREAD) std::cout << "TEST_STDTHREAD"<< std::endl; auto task = std::async(std::launch::async, [&]() { create_context(); }); task.wait(); std::cout << "Done"<< std::endl; #elif defined(TEST_TBB) std::cout << "TEST_TBB"<< std::endl; std::atomic_bool done(false); EnqueueLambda([&]() { create_context(); done = true; return false; }); #if 1 // Try waiting inside scheduler loop SpawnAndWaitLambda([&]() { if (done) { std::cout << "Done"<< std::endl; return false; } return true; }); #else // This also fails if we just spin loop while (!done) ; std::cout << "Done"<< std::endl; #endif #else std::cout << "TEST_SERIAL"<< std::endl; create_context(); std::cout << "Done"<< std::endl; #endif return 0; }
TCE Open Date:
Friday, December 6, 2019 - 12:51