From: Kenneth 'Bessarion' Boyd on
On Jan 5, 1:15 pm, viboes <vicente.bo...(a)wanadoo.fr> wrote:
> On Jan 4, 4:19 pm, Ulrich Eckhardt <dooms...(a)knuut.de> wrote:

> My context is Software Transactional Memory (STM). The shared
> transactional objects need to be cached on transaction specific
> objects. The pointers these transactional objects contains are
> pointers to other transactional objects.
>
> The idea I have in mind is that this cache don't need to do a deep
> copy of the transactional object, but just a shallow copy, as the STM
> system will take care of the copy of these pointee transactional
> objects when modified. In addition I want the STM mechanism to
> interfere as less as possible with the user space. That is why I don't
> want to use copy constructor, assignment, neither class specific new/
> delete operators.

Ok: you need a shallow copy that bypasses the main class invariants
for efficiency reasons.

> The STM library I'm working on requires that any transactional object
> inherits from
>
> class base_transaction_object {
> public:
> virtual base_transaction_object*
> make_cache(transaction* t) const = 0;
> virtual void copy_cache(
> base_transaction_object const * const) = 0;
> virtual void delete_cache()=0;
> virtual ~base_transaction_object() {};
> ...
> };
>
> I omit here why the STM library need this.

Don't have full control of the inheritance diagram: ok. Note that
this means std::memcpy close to automatically fails to make a valid
copy (you might get lucky on a very nice target).

> IMO there is no need to call the destructor of Final. The reason is
> that this object is not a real one, is a cache of other real object.

Yes: you're returning a doppleganger FinalCache object (which
hopefully has a trivial destructor) in place of a Final object.
Furthermore, this FinalCache object has to pretend to be a subclass of
base_transaction_object when it isn't.

I can't imagine how to implement this without invoking Undefined
Behavior all over the place, rather than just here. You will need a
zoo of test cases to verify that these changes work with your target
compiler (and verify that merely upgrading doesn't break things, let
alone changing compiler vendors).

> For classes that have no trivial copy semantics we can yet do a
> shallow copy, but as I understand it now, not without the help of
> user. I'm wondering if it is worth to require the user to define the
> following shallow functions:
>
> struct shallow_t {};
> const shallow_t shallow = {};
>
> // Shallow copy constructor
> C(C const&, shallow_t);
> // Shallow assignement
> C& shallow_assign(C const&);

This is reasonable, yes.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Goran on
On Jan 6, 2:00 am, viboes <vicente.bo...(a)wanadoo.fr> wrote:
> Could you comment on the approach I have presented on my last post?

Well, your post is too long and too complicated for my comprehension
capabilities now...

However, my feeling is that you have pointers to transactional objects
inside your transactional objects and that you want to avoid copying
them. If that is the case, couldn't you mandate the use of smart
pointers for transactional objects and get rid of copying that way? I
would be hugely surprised if some existing STM in C or C++ weren't
doing the same already. This is because, typically (well, at least in
my mind), working with transactional memory goes something like this:

type t(transactionalObject->read());
t.modify(params);
transactionalObject->write(t);

Now, here, transactionalObject is a wrapper (probably through a smart
pointer) of the actual data type that is subject to STM. t might or
might not contain other transactional object smart pointers. When you
invoke write, a copy of t is stored in transactionalObject. If
type::modify modifies embedded transactional objects, well, they have
another copy anyhow, regardless of your shallow/deep distinction,
because you did

t.embeddedTransactionalObject->write(newValue);

But either way, you only copy smart pointers to these embedded
transactional objects, which is +/- cheap.

(Or else, I am way off the mark, and indeed I have no practical
experience with an STM system.)

Goran.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: viboes on
On Jan 6, 9:39 am, "Kenneth 'Bessarion' Boyd" <zaim...(a)zaimoni.com>
wrote:
> On Jan 5, 1:15 pm, viboes <vicente.bo...(a)wanadoo.fr> wrote:
>
> > On Jan 4, 4:19 pm, Ulrich Eckhardt <dooms...(a)knuut.de> wrote:
> > My context is Software Transactional Memory (STM). The shared
> > transactional objects need to be cached on transaction specific
> > objects. The pointers these transactional objects contains are
> > pointers to other transactional objects.
>
> > The idea I have in mind is that this cache don't need to do a deep
> > copy of the transactional object, but just a shallow copy, as the STM
> > system will take care of the copy of these pointee transactional
> > objects when modified. In addition I want the STM mechanism to
> > interfere as less as possible with the user space. That is why I don't
> > want to use copy constructor, assignment, neither class specific new/
> > delete operators.
>
> Ok: you need a shallow copy that bypasses the main class invariants
> for efficiency reasons.

Not only efficiency, I'm looking to don't interfere with the user
space also.

> > The STM library I'm working on requires that any transactional object
> > inherits from
>
> > class base_transaction_object {
> > public:
> > virtual base_transaction_object*
> > make_cache(transaction* t) const = 0;
> > virtual void copy_cache(
> > base_transaction_object const * const) = 0;
> > virtual void delete_cache()=0;
> > virtual ~base_transaction_object() {};
> > ...
> > };
>
> > I omit here why the STM library need this.
>
> Don't have full control of the inheritance diagram: ok. Note that
> this means std::memcpy close to automatically fails to make a valid
> copy (you might get lucky on a very nice target).

Yes I agree. I use std::memcpy now only when the class has Trivial
Copy semantics.

> > IMO there is no need to call the destructor of Final. The reason is
> > that this object is not a real one, is a cache of other real object.
>
> Yes: you're returning a doppleganger FinalCache object (which
> hopefully has a trivial destructor) in place of a Final object.
> Furthermore, this FinalCache object has to pretend to be a subclass of
> base_transaction_object when it isn't.

Currently the returned object inherits from base_transaction_object as
it is an instance of the same class.

> I can't imagine how to implement this without invoking Undefined
> Behavior all over the place, rather than just here. You will need a
> zoo of test cases to verify that these changes work with your target
> compiler (and verify that merely upgrading doesn't break things, let
> alone changing compiler vendors).

I don't pretend to implement what you said, so no need to imagine how.

> > For classes that have no trivial copy semantics we can yet do a
> > shallow copy, but as I understand it now, not without the help of
> > user. I'm wondering if it is worth to require the user to define the
> > following shallow functions:
>
> > struct shallow_t {};
> > const shallow_t shallow = {};
>
> > // Shallow copy constructor
> > C(C const&, shallow_t);
> > // Shallow assignment
> > C& shallow_assign(C const&);
>
> This is reasonable, yes.

Happy to hear,
Vicente


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]