pvAccessCPP  7.1.2
Changes to ChannelProvider ownership rules

Table of Contents

Major series 6.x includes changes to the rules for when user code may store strong and/or weak references to epics::pvAccess::ChannelProvider and related classes.

These rules exist to prevent strong reference loops from forming.

Operation <-> Requester

One change is the reversal of the allowed relationship between an Operation and its associated Requester (see Operation and Requester for definitions).

Prior to 6.0.0 an Operation was required to hold a strong reference to its Requester. This prevented the Requester from holding a strong ref to the Operation.

This was found to be inconvienent and frequently violated. Beginning with 6.0.0 an Operation is prohibited from holding a strong reference to its Requester.

Porting

Legecy code does not store a strong reference to Requesters will see that they are immediately destory.

An example where the Operation is a ChannelGet and the Requester is ChannelGetRequester.

// Bad example!
epics::pvAccess::Channel::shared_pointer chan = ...;
epics::pvAccess::ChannelGet::shared_pointer get;
{
epics::pvAccess::ChannelGetRequester::shared_pointer req(new MyRequester(...));
get = chan->createChannelGet(req, epics::pvData::createRequest("field()"));
// 'req' is only strong ref.
// MyRequester::~MyRequester() called here
// MyRequester::getDone() never called!
}

It is necessary to maintain a strong reference to the ChannelRequester as long as callbacks are desired.

Note
Legacy code could be modified to strong each Requester alongside the associated Operation.

New code may utilize the new ownership rules and store the Operation in a custom Requester.

struct MyRequester : public epics::pvAccess::ChannelGetRequester {
epics::pvAccess::ChannelGet::shared_pointer get;
...
};
epics::pvAccess::ChannelGetRequester::shared_pointer req(new MyRequester(...));
epics::pvAccess::Channel::shared_pointer chan = ...;
req->get = chan->createChannelGet(req, epics::pvData::createRequest("field()"));

Must store Operation reference

Beginning with 6.0.0, all create methods of epics::pvAccess::ChannelProvider and epics::pvAccess::Channel are required to return shared_ptr which are uniquely ownered by the caller and are not stored internally.

Thus the caller of a create method must keep a reference to each Operation or the Operation will be destoryed.

Prior to 6.0.0 some providers, notibly the "pva" provider, did not do this. It was thus (sometimes) necessary to explicitly call a destory() method to fully dispose of an Operation. Failure to do this resulted in a slow resource leak.

Beginning with 6.0.0 an Operation must not rely on user code to call a destory() method.

Porting

Legecy code may be relying on these internal references to keep an Operation alive.

Beginning with 6.0.0 the shared_ptr returned by any create method must be stored or the Operation will be immediately destroy'd.

Note
Beginning with 6.0.0 use of the epics::pvAccess::ChannelRequester interface is optional and may be omitted when calling createChannel().