On 30/12/2014 15:01, Gruenke,Matt wrote:
Upon further consideration...
-----Original Message----- From: Gruenke,Matt Sent: Tuesday, December 30, 2014 8:49 To: boost@lists.boost.org Subject: RE: [boost] Synchronization (RE: [compute] review)
-----Original Message----- From: Boost [mailto:boost-bounces@lists.boost.org] On Behalf Of Thomas M Sent: Tuesday, December 30, 2014 7:37 To: boost@lists.boost.org Subject: Re: [boost] Synchronization (RE: [compute] review)
c) a guard for a command-queue as whole [possibly guards for other classes as well]
Why? Convenience?
Unless you're using it as a shorthand for waiting on individual events or wait_lists, there's no need. The event_queue is internally refcounted. When the refcount goes to zero, the destructor will block on all outstanding commands.
To some degree it's convenience, that's correct. I find this both more explicit and straightforward to code: command_queue::guarantee cqg(cq); cq.enqueue_write_buffer_async(...); transform(..., cqg); cq.enqueue_read_buffer_async(...); ... than wait_list wl; wait_list::guarantee wlg(wl); wl.insert(cq.enqueue_write_buffer_async(...)); wl.insert(cq.enqueue_task(kern, wl)); wl.insert(cq.enqueue_read_buffer_async(...)); I don't see anything wrong with a compact form which also emphasizes the grouped nature of all following commands if that's the situation; also I don't really know what enqueue_task shall exactly look like, but the STL-ish similarity is lost though.
I should've listed to myself more carefully. I think this means command_queue-level guarantees aren't necessary or useful, because you've either got:
1) A local command_queue, with a refcount of 1, in which case it will block upon destruction.
2) A copy of a nonlocal command_queue, in which case there may be unrelated commands in the queue.
I cannot fully follow this; let's presume the convenience aspect is appreciated, then one reason to offer these guards is to make sure that other objects, e.g. memory objects, still persist while an asynchronous operation might use them: std::vector<float> host_data(...); cq.enqueue_write_buffer_async(..., &host_data.front()); // here run some algorithm(s) cq.enqueue_read_buffer_async(..., &host_data.front()); If the command_queue is local then it must become constructed after host_data, as otherwise at the time of the queue's destruction, i.e. when it waits for the enqueued operations to finish, host_data is already dead. To me an explicit guard which I can place flexibly into any block/scope is ways more clearer (and safer) to handle than declaration ordering of "primary" objects. As for the second point I don't see how this alters the game. Every scope must ensure that its relevant operations have completed before resources required by the operations become released; if that requires that commands enqueued earlier (outside) must also complete so shall it be. I am not saying that such a command-queue guarantee is always the right thing. Thomas