diff --git a/.travis.yml b/.travis.yml index d6c67ad3..7d83131d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,12 +4,12 @@ compiler: - clang before_install: - sudo apt-get update -qq - - sudo apt-get install -qq fglrx=2:8.960-0ubuntu1 opencl-headers libboost-chrono1.48-dev libboost-date-time1.48-dev libboost-test1.48-dev libboost-system1.48-dev libboost-filesystem1.48-dev libboost-timer1.48-dev libboost-program-options1.48-dev python-yaml lcov libopencv-dev + - sudo apt-get install -qq fglrx=2:8.960-0ubuntu1 opencl-headers libboost-chrono1.48-dev libboost-date-time1.48-dev libboost-test1.48-dev libboost-system1.48-dev libboost-filesystem1.48-dev libboost-timer1.48-dev libboost-program-options1.48-dev libboost-thread1.48-dev python-yaml lcov libopencv-dev - gem install coveralls-lcov script: - mkdir -p build - cd build - - cmake -DBOOST_COMPUTE_BUILD_TESTS=ON -DBOOST_COMPUTE_BUILD_EXAMPLES=ON -DBOOST_COMPUTE_BUILD_BENCHMARKS=ON -DBOOST_COMPUTE_USE_OFFLINE_CACHE=ON -DBOOST_COMPUTE_ENABLE_COVERAGE=ON -DBOOST_COMPUTE_HAVE_OPENCV=ON -DCMAKE_CXX_FLAGS="-Wall -pedantic -Werror -Wno-variadic-macros -Wno-long-long -Wno-shadow" .. + - cmake -DBOOST_COMPUTE_BUILD_TESTS=ON -DBOOST_COMPUTE_BUILD_EXAMPLES=ON -DBOOST_COMPUTE_BUILD_BENCHMARKS=ON -DBOOST_COMPUTE_USE_OFFLINE_CACHE=ON -DBOOST_COMPUTE_ENABLE_COVERAGE=ON -DBOOST_COMPUTE_HAVE_OPENCV=ON -DBOOST_COMPUTE_THREAD_SAFE=ON -DCMAKE_CXX_FLAGS="-Wall -pedantic -Werror -Wno-variadic-macros -Wno-long-long -Wno-shadow" .. - make -j8 - ./example/list_devices - ctest --output-on-failure diff --git a/CMakeLists.txt b/CMakeLists.txt index 0403e2c0..9c94fbde 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,15 @@ if(${BOOST_COMPUTE_USE_CPP11}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") endif() +# thread-safety options +option(BOOST_COMPUTE_THREAD_SAFE "Compile with BOOST_COMPUTE_THREAD_SAFE defined" OFF) +if(${BOOST_COMPUTE_THREAD_SAFE}) + add_definitions(-DBOOST_COMPUTE_THREAD_SAFE) + if(${BOOST_COMPUTE_USE_CPP11}) + add_definitions(-DBOOST_COMPUTE_HAVE_THREAD_LOCAL) + endif() +endif() + # optional third-party libraries option(BOOST_COMPUTE_HAVE_EIGEN "Have Eigen" OFF) option(BOOST_COMPUTE_HAVE_OPENCV "Have OpenCV" OFF) diff --git a/doc/faq.qbk b/doc/faq.qbk index a4c202ec..490c5535 100644 --- a/doc/faq.qbk +++ b/doc/faq.qbk @@ -129,6 +129,18 @@ which provides a std::vector-like interface to a region of host-memory and can be used directly with all of the Boost.Compute algorithms. +[h3 Is Boost.Compute thread-safe?] + +The low-level Boost.Compute APIs offer the same thread-safety guarantees as +the underyling OpenCL library implementation. However, the high-level APIs +make use of a few global static objects for features such as automatic program +caching which makes them not thread-safe by default. + +To compile Boost.Compute in thread-safe mode define `BOOST_COMPUTE_THREAD_SAFE` +before including any of the Boost.Compute headers. By default this will require +linking your application/library with the Boost.Thread library. + + [h3 How can I contribute?] We are actively seeking additional C++ developers with experience in diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 7458b450..e1f75a99 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -31,6 +31,10 @@ if (${BOOST_COMPUTE_USE_OFFLINE_CACHE}) set(EXAMPLE_BOOST_COMPONENTS ${EXAMPLE_BOOST_COMPONENTS} system filesystem) endif() +if(${BOOST_COMPUTE_THREAD_SAFE} AND NOT ${BOOST_COMPUTE_USE_CPP11}) + set(EXAMPLE_BOOST_COMPONENTS ${EXAMPLE_BOOST_COMPONENTS} thread) +endif() + find_package(Boost 1.48 REQUIRED COMPONENTS ${EXAMPLE_BOOST_COMPONENTS}) include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) diff --git a/include/boost/compute/detail/global_static.hpp b/include/boost/compute/detail/global_static.hpp new file mode 100644 index 00000000..0f4bbce2 --- /dev/null +++ b/include/boost/compute/detail/global_static.hpp @@ -0,0 +1,37 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013-2014 Kyle Lutz +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://kylelutz.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#ifndef BOOST_COMPUTE_DETAIL_GLOBAL_STATIC_HPP +#define BOOST_COMPUTE_DETAIL_GLOBAL_STATIC_HPP + +#include + +#ifdef BOOST_COMPUTE_THREAD_SAFE +# ifdef BOOST_COMPUTE_HAVE_THREAD_LOCAL + // use c++11 thread local storage +# define BOOST_COMPUTE_DETAIL_GLOBAL_STATIC(type, name, ctor) \ + thread_local type name ctor; +# else + // use thread_specific_ptr from boost.thread +# include +# define BOOST_COMPUTE_DETAIL_GLOBAL_STATIC(type, name, ctor) \ + static ::boost::thread_specific_ptr< type > BOOST_PP_CAT(name, _tls_ptr_); \ + if(!BOOST_PP_CAT(name, _tls_ptr_).get()){ \ + BOOST_PP_CAT(name, _tls_ptr_).reset(new type ctor); \ + } \ + static type &name = *BOOST_PP_CAT(name, _tls_ptr_); +# endif +#else + // no thread-safety, just use static +# define BOOST_COMPUTE_DETAIL_GLOBAL_STATIC(type, name, ctor) \ + static type name ctor; +#endif + +#endif // BOOST_COMPUTE_DETAIL_GLOBAL_STATIC_HPP diff --git a/include/boost/compute/detail/program_cache.hpp b/include/boost/compute/detail/program_cache.hpp index d9873d0c..76b8d59e 100644 --- a/include/boost/compute/detail/program_cache.hpp +++ b/include/boost/compute/detail/program_cache.hpp @@ -20,6 +20,7 @@ #include #include #include +#include namespace boost { namespace compute { @@ -66,7 +67,7 @@ inline boost::shared_ptr get_program_cache(const context &context { typedef lru_cache > cache_map; - static cache_map caches(8); + BOOST_COMPUTE_DETAIL_GLOBAL_STATIC(cache_map, caches, (8)); boost::shared_ptr cache = caches.get(context.get()); if(!cache){ diff --git a/perf/CMakeLists.txt b/perf/CMakeLists.txt index 3c029628..6727689f 100644 --- a/perf/CMakeLists.txt +++ b/perf/CMakeLists.txt @@ -6,6 +6,10 @@ if (${BOOST_COMPUTE_USE_OFFLINE_CACHE}) set(PERF_BOOST_COMPONENTS ${PERF_BOOST_COMPONENTS} filesystem) endif() +if(${BOOST_COMPUTE_THREAD_SAFE} AND NOT ${BOOST_COMPUTE_USE_CPP11}) + set(PERF_BOOST_COMPONENTS ${PERF_BOOST_COMPONENTS} thread) +endif() + find_package(Boost 1.48 REQUIRED COMPONENTS ${PERF_BOOST_COMPONENTS}) include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 01d1ba87..6b6ad906 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -3,8 +3,12 @@ include_directories(../include) set(BOOST_COMPONENTS unit_test_framework) if (${BOOST_COMPUTE_USE_OFFLINE_CACHE}) - set(BOOST_COMPONENTS ${BOOST_COMPONENTS} system filesystem) - add_definitions(-DBOOST_COMPUTE_USE_OFFLINE_CACHE) + set(BOOST_COMPONENTS ${BOOST_COMPONENTS} system filesystem) + add_definitions(-DBOOST_COMPUTE_USE_OFFLINE_CACHE) +endif() + +if(${BOOST_COMPUTE_THREAD_SAFE} AND NOT ${BOOST_COMPUTE_USE_CPP11}) + set(BOOST_COMPONENTS ${BOOST_COMPONENTS} thread) endif() find_package(Boost 1.48 REQUIRED COMPONENTS ${BOOST_COMPONENTS})