Subject: Re: [boost] [compute] Some questions
From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2014-12-23 15:55:57
On Tue, Dec 23, 2014 at 7:29 PM, Kyle Lutz <kyle.r.lutz_at_[hidden]> wrote:
> On Tue, Dec 23, 2014 at 1:20 AM, Andrey Semashev
> <andrey.semashev_at_[hidden]> wrote:
>> 1. When you define a kernel (e.g. with the BOOST_COMPUTE_FUNCTION
>> macro), is this kernel supposed to be in C? Can it reference global
>> (namespace scope) objects and other functions? Other kernels?
> Yes, the source code for OpenCL kernels and functions is specified in
> OpenCL C which is a dialect of C99 with extensions for vectorized
Does this mean that the compiler has to support OpenCL in order to be
able to use Boost.Compute? Or its specific features? If yes, can this
be mentioned in the docs (with the list of the affected features, if
Also, I don't quite understand, how the kernel source code which I
supply to BOOST_COMPUTE_FUNCTION is then compiled into kernel. Is this
source code just stringized and not actually compiled when the
application is built?
> There are a few ways to specific kernel functions which reference
> global C++ values. One is the BOOST_COMPUTE_CLOSURE() macro  which
> works similarly to BOOST_COMPUTE_FUNCTION(), but also allows a
> lambda-like capture list of C++ values.
>> 2. When is the kernel compiled and uploaded to the device? Is it
>> possible to cache and reuse the compiled kernel?
> If writing a custom kernel, the kernel is built when the
> "program::build()" method is called. Internally, the higher-level
> algorithms compile programs when they're needed and store them in a
> global program cache.
> And yes, compiled program and kernel objects can be stored and re-used
> (this is strongly recommended). Boost.Compute provides the
> program_cache class  which is used stores frequently used programs
> as compiled objects.
So, e.g. a kernel defined with BOOST_COMPUTE_FUNCTION will be compiled
when first used, and then saved in some global program_cache, is that
correct? Also, captured arguments of BOOST_COMPUTE_CLOSURE will be
evaluated only once, when the kernel is built?
>> 3. Why is the library not thread-safe by default? I'd say, we're long
>> past single-threaded systems now, and having to always define the
>> config macro is a nuisance.
> I would very much like to have it thread-safe by default. This is a
> problem however with keeping the library header-only and useable with
> C++03 compilers. The BOOST_COMPUTE_THREAD_SAFE macro basically just
> instructs Boost.Compute to use the C++11 "thread_local" specifier for
> global objects instead of "static". With C++03 compilers, this will
> use boost::thread_specific_ptr<> which then requires users to also
> link to Boost.Thread.
> That said, I still don't think it's ideal and I am very open to
> ideas/patches which improve this.
Personally, I see no big problem with dependency on Boost.Thread in
C++03. However, it is quite possible to use system API to implement
TLS in header-only library.
On POSIX systems it is quite trivial with pthread_once and
pthread_key* API. On Windows you can use Interlocked* functions or
Boost.Atomic to implement something similar to pthread_once and Tls*
functions for the TLS itself. The tricky part is the TLS cleanup,
which can be done with help of the Windows thread pool. You can use
RegisterWaitForSingleObject to schedule a wait operation on the handle
of the thread that sets the thread-local value. When the thread exits,
the pool will invoke the callback you passed to
RegisterWaitForSingleObject, where you can clean the TLS value. The
important difference from thread_local and Boost.Thread is that the
callback is called in a thread different from the one that initialized
the TLS value, but for various cleanup routines this should not
You can see how it's done in Boost.Sync: