I'm glad to see I'm not the only one trying to use shared. I tried to use it 
with 2.031 and rapidly hit bug after bug... I submitted several bug reports for 
basic functionality, and none of it appeared in the changelog.

http://d.puremagic.com/issues/show_bug.cgi?id=3089
http://d.puremagic.com/issues/show_bug.cgi?id=3090
http://d.puremagic.com/issues/show_bug.cgi?id=3091



Jeremie Pelletier Wrote:

> I decided to play once again with shared and see what 2.032 is capable of. 
> Turns out a lot of the previous issues I was having last time are gone, 
> however, there are still a few things left which prevent me from rewriting my 
> code.
> 
> The first issue that jumped to my face straight away was how 'shared const' 
> methods are not callable from 'shared' objects.
> 
> shared class Foo {
>       void bar() const;
> }
> auto foo = new Foo; // foo is of type shared(Foo)
> foo.bar; //  Error: function Foo.bar () shared const is not callable using 
> argument types () shared
> 
> Considering how 'const' methods can be called from mutable objects, this 
> looks like either a bug or a really awkward feature to me. Sending a 
> shared(Foo) to a method expecting a shared(const(Foo)) also triggers a 
> similar error from the compiler.
> 
> The other issue may be an intended feature, but it doesn't sound practical to 
> me. Marking a method as shared assumes all used properties in the method's 
> scope are also shared. Here is an example to illustrate my point:
> 
> class SimpleReader {
>    this(LocalFile file) { _stream = new FileInputStream(file); }
>    ...
> private:
>     synchronized void read(ubyte[] buf, long offset) {
>         _stream.seek(offset);
>         _stream.read(buf);
>     }
>     FileInputStream _stream;
> }
> 
> The FileInputStream here is a generic blocking binary stream which is not 
> thread-safe by design. The reader is a composite class where every instance 
> has its own unique stream instance and use it to implement asynchronous reads 
> over the file format it abstracts, which in my case is a specialized 
> read-only archive using a lot of random accesses from different threads.
> 
> This is where the issue shows its ugly head. The 'synchronized' keyword tags 
> the read method as shared, which in itself is quite neat, what is annoying 
> however is that it also changes the type of _stream in the method's scope to 
> shared(FileInputStream) and therefore triggers compiler errors because 
> _stream.seek and _stream.read are not shared:
> 
> Error: function FileInputStream.read (ubyte[]) is not callable using argument 
> types (ubyte[]) shared
> 
> While it may be an attempt to keep shared usage safe, it isn't very 
> practical. The stream object here is not shared because it is not 
> thread-safe. While it may be used by different threads, it is unique to the 
> reader's context and its accesses are synchronized by the reader, the stream 
> should therefore be completely oblivious to the fact it is being used by 
> different threads.
> 
> Maybe this could be the time to implement an unique qualifier; this is a 
> context where having _stream be of type unique(FileInputStream) would solve 
> the problem and allow further compiler optimizations. I don't know if it can 
> be done with templates, and without any overhead whatsoever. I know I would 
> much rather see unique(Foo) than Unique!Foo, and it would allow the use of 
> 'is(foo : unique)'.
> 
> Furthermore, tagging a method with shared does not make it thread-safe, it 
> may however use synchronized within its scope to protect its shared or unique 
> data. This may be confusing when calling shared methods vs calling 
> synchronized methods; one may think the shared one is not thread-safe and 
> optionally synchronize the call, resulting in another monitor being used for 
> nothing, or no monitor being used at all:
> 
> class Foo {
>     shared void bar() {
>         // Do stuff with local or immutable data
>         synchronized(this) { /* do stuff with shared data */ }
>     }
>     shared void bar2() {
>         // Do stuff on shared data
>     }
> }
> 
> Someone seeing only the prototype of Foo.bar may assume the method is not 
> thread-safe and call it as 'synchronized(foo) foo.bar()'. Just like they 
> could see the prototype of bar2 and assume it is thread-safe, calling it as 
> 'foo.bar2()'.
> 
> What could be a good design against this sort of misleading behavior?
> 
> Phew, that's about enough issues and questions for now :)

Reply via email to