Thread overview
Shared object must have synchronized interface?
May 12, 2013
Domain
May 12, 2013
Jonathan M Davis
May 12, 2013
Domain
May 12, 2013
Jonathan M Davis
May 12, 2013
class A
{
    public synchronized void test1()
    {
    }

    public void test2()
    {
    }
}

int main(string[] argv)
{
    auto a1 = new shared(A)();
    a1.test1();
    a1.test2();

    auto a2 = new A();
    a2.test1();
    a2.test2();
}

Error: function main.A.test2 () is not callable using argument types () shared
Error: function main.A.test1 () shared is not callable using argument types ()

So, if I want a class support both shared and non-shared, I must override all method?

May 12, 2013
On Sunday, May 12, 2013 04:54:25 Domain wrote:
> class A
> {
>      public synchronized void test1()
>      {
>      }
> 
>      public void test2()
>      {
>      }
> }
> 
> int main(string[] argv)
> {
>      auto a1 = new shared(A)();
>      a1.test1();
>      a1.test2();
> 
>      auto a2 = new A();
>      a2.test1();
>      a2.test2();
> }
> 
> Error: function main.A.test2 () is not callable using argument
> types () shared
> Error: function main.A.test1 () shared is not callable using
> argument types ()
> 
> So, if I want a class support both shared and non-shared, I must override all method?

Overload technically, but yes (override means implementing the same function that was in a base class with the same signature (save perhaps for a covariant return type), whereas overload means providing a function with the same name but a different signature).

I believe that the way that shared objects are typically handled at this point is that if you want to call functions on them, you protect them within a synchronized block or with a mutex, and then you cast them to non-shared while you use it (and treat it as shared again once you've exited the synchronized block or unlocked the mutex). Actually trying to call functions on a shared object is a royal pain precisely because you have to overload everything. But as long as access to the object is appropriately protected, it's perfectly safe to cast the object to non-shared in order to use it. You just have to make sure that access to the object is indeed protected so that only one thread is accessing it while it's being operated on as non-shared (or you'll get really nasty bugs).

A class with synchronized functions can be used to protect a shared object, but the functions being called on the shared object would still have to be shared (or the shared object would have to be non-shared) in order to call them.

- Jonathan M Davis
May 12, 2013
On Sunday, 12 May 2013 at 03:44:16 UTC, Jonathan M Davis wrote:
> On Sunday, May 12, 2013 04:54:25 Domain wrote:
>> class A
>> {
>>      public synchronized void test1()
>>      {
>>      }
>> 
>>      public void test2()
>>      {
>>      }
>> }
>> 
>> int main(string[] argv)
>> {
>>      auto a1 = new shared(A)();
>>      a1.test1();
>>      a1.test2();
>> 
>>      auto a2 = new A();
>>      a2.test1();
>>      a2.test2();
>> }
>> 
>> Error: function main.A.test2 () is not callable using argument
>> types () shared
>> Error: function main.A.test1 () shared is not callable using
>> argument types ()
>> 
>> So, if I want a class support both shared and non-shared, I must
>> override all method?
>
> Overload technically, but yes (override means implementing the same function
> that was in a base class with the same signature (save perhaps for a covariant
> return type), whereas overload means providing a function with the same name
> but a different signature).
>
> I believe that the way that shared objects are typically handled at this point
> is that if you want to call functions on them, you protect them within a
> synchronized block or with a mutex, and then you cast them to non-shared while
> you use it (and treat it as shared again once you've exited the synchronized
> block or unlocked the mutex). Actually trying to call functions on a shared
> object is a royal pain precisely because you have to overload everything. But
> as long as access to the object is appropriately protected, it's perfectly
> safe to cast the object to non-shared in order to use it. You just have to
> make sure that access to the object is indeed protected so that only one
> thread is accessing it while it's being operated on as non-shared (or you'll
> get really nasty bugs).
>
> A class with synchronized functions can be used to protect a shared object,
> but the functions being called on the shared object would still have to be
> shared (or the shared object would have to be non-shared) in order to call
> them.
>
> - Jonathan M Davis

Thanks for the explanation. Yes, I mean overload. I know the difference, sorry for my pool English.

Sure, we can use synchronized block instead of synchronized function. But it's inconvenient. Why not the compiler automatically convert the non-synchronized function to synchronized function when the object declare as shared?
May 12, 2013
On Sunday, May 12, 2013 06:34:48 Domain wrote:
> Sure, we can use synchronized block instead of synchronized function. But it's inconvenient. Why not the compiler automatically convert the non-synchronized function to synchronized function when the object declare as shared?

The actual code generated for a synchronized function would be different, and automatically handling of locking like that would actually be very error-prone - particularly when you consider the potential for deadlocks. Do you really want to end up with deadlocks because the compiler chose to automatically insert locks where you didn't ask for them?

Another thing to note is that on some level, shared code is _supposed_ to be inconvenient. You shouldn't be doing it often. It's supposed to be possible but not necessarily friendly. It's quite possible that we haven't hit the right balance on that, and it's too much of a pain to do right, but it was never intended that any of that be automatic or invisible. Code dealing with shared objects should be carefully segregated from normal code.

synchronized was designed with the idea that you would create classes that were specifcally for synchronization and not that normal code would be synchronized. In fact, TDPL calls for making entire classes synchronized or not rather than individual functions (though it's not currently implemented that way in the compiler - you can still have both synchronized and unsynchronized functions in the same class). So, if you intended to use synchronized functions, you'd set it up so that the whole object was set up that way and only ever used that way.

I suggest that you read the chapter on concurrency in TDPL. That particular chapter is actually available online for free:

http://www.informit.com/articles/article.aspx?p=1609144

- Jonathan M Davis