1

I've got some C code that I'm hoping to transition towards C++, and as a first step, I'm trying to get things compilable with a C++ compiler (g++ right now).

It uses some shared memory segments for IPC and the pointers to these are declared as volatile:

volatile my_rec_t *myRec;

(Where my_rec_t is just a plain old data structure, and myRec is accessed as an array of these).

I'm having some problems with the volatility of this data structure: C++ seems to require a whole lot more casting than C did, and I'm not quite sure I understand why...

There are some auto-generated accessor functions to get/set a field in the shared memory structure (currently all C-style code). This is working for primitive data types but where one of the fields in my_rec_t is itself a struct, it produces errors:

int setIndexNode( int myRecNo, index_node_t indexNode )
{
  myRec[ myRecNo ].indexNode = indexNode;
  return TRUE;
}

In C++ this generates the following: error: passing 'volatile index_node_t' as 'this' argument of 'index_node_t& index_node_t::operator=(const index_node_t&)' discards qualifiers. And for getting the value:

index_node_t getIndexNode( int myRecNo )
{
  return myRec[ myRecNo ].indexNode;
}

The error is error: no matching function for call to 'index_node_t::index_node_t(volatile index_node_t&)'

The get problem is more baffling to me because structs are passed by value, so the returned value, as a copy, is naturally going to lose it's volatility? For the set case, surely volatility is more important in terms of reading the data in case it is changed by another process - I don't really know what volatile means when writing to the data location.

NB: the code snippets are cut down for the purposes of this example, there is various locking and bounds checking code in there :)

asc99c
  • 3,815
  • 3
  • 31
  • 54
  • Related: http://stackoverflow.com/questions/4644296/cant-assign-an-object-to-a-volatile-object It looks like you've got some boilerplate ahead of you :( – ecatmur May 27 '14 at 14:33
  • 1
    Also, don't succumb to the temptation to cast away `volatile`: http://stackoverflow.com/questions/7367580/c-c-casting-away-volatile-considered-harmful?lq=1 – ecatmur May 27 '14 at 14:34
  • Is `getIndexNode` really intending to provide a point-in-time read of the value, removing its `volatile`ness? – Mark B May 27 '14 at 15:03
  • @MarkB yeah it is the current value copied from the database. Locking of the records when needed is dealt with elsewhere. – asc99c May 27 '14 at 15:43
  • @ecatmur I'm currently using the const_cast to make this work. I could add all the boilerplate stuff into the core platform but whenever anyone copies any old C plugins in it would need the same doing for them. And at least for a step 1 C++ compatible platform, I don't want to require all that. – asc99c May 27 '14 at 15:45
  • Also related: http://stackoverflow.com/questions/17217300/why-am-i-not-provided-with-a-default-copy-constructor-from-a-volatile – ecatmur May 27 '14 at 16:02
  • 1
    Declaring it `volatile` is probably (not guaranteed to be) wrong to begin with. `volatile` is not a synchronisation mechanism. – n. m. could be an AI May 27 '14 at 16:41
  • Nor is it meant to be. It's to stop the compiler optimising away variable accesses that it thinks are redundant. It's just marking that the data is in shared memory and may potentially be updated by another process at any time. – asc99c May 27 '14 at 17:58

2 Answers2

0

For getIndexNode the answer appears to be fairly straightforward: const_cast away the volatility before returning it, since that's your intended semantic. Note that as long as the memory being pointed to by the volatile pointer is not originally declared volatile, casting it away is perfectly well defined.

For the copy assignment operator you could try making it volatile, although you haven't shown enough code to say for sure if that will fix your problem. For example index_node_t& index_node_t::operator=(const index_node_t&) volatile.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • 1
    Casting away volatile is undefined behavior: http://stackoverflow.com/questions/7367580/c-c-casting-away-volatile-considered-harmful?lq=1 – ecatmur May 27 '14 at 16:04
0

It's never safe to cast away the volatility; you can only use member functions that are marked as volatile.

However just doing this does not guarantee safety; the operations are probably non-atomic so a thread switch could rek them. You'll have to also make sure via some locking mechanism or otherwise that when you are using one of these volatile structs, the operation will complete without the struct's data being changed by something else during the operation.

It may turn out to be easier not to use these structs in your shared memory ,but to use some bloc data that you can read and write atomically via an OS function (if such a thing exists).

M.M
  • 138,810
  • 21
  • 208
  • 365