Re: aa.keys, synchronized and shared
On Monday, 14 November 2022 at 07:57:16 UTC, Kagamin wrote: This works for me: ``` shared SyncAA!(string,string) saa; void f() { saa=new shared SyncAA!(string,string)("1","2"); saa.keys(); saa["12"]="34"; saa.remove("12"); } ``` The strange error message I got was because I initialized the variable at module level, that doesn't work when you have a constructor. It worked when I moved it into a module constructor.
Re: aa.keys, synchronized and shared
This works for me: ``` synchronized final class SyncAA(K, V) { this(K key, V val) { sharedTable[key]=val; } V opIndex(K key) { return sharedTable[key]; } V opIndexAssign(V value, K key) { return sharedTable[key]=value; } const(K[]) keys() const { return unsharedTable.keys; } void remove(K key) { sharedTable.remove(key); } V get(K key, lazy V defaultValue=V.init) { auto p = key in sharedTable; return p ? *p : defaultValue; } private: V[K] sharedTable; inout(V[K]) unsharedTable() inout { return cast(inout(V[K]))sharedTable; } } shared SyncAA!(string,string) saa; void f() { saa=new shared SyncAA!(string,string)("1","2"); saa.keys(); saa["12"]="34"; saa.remove("12"); } ```
Re: aa.keys, synchronized and shared
On Friday, 11 November 2022 at 14:19:31 UTC, Kagamin wrote: Try this: ``` private: V[K] sharedTable; ref inout(V[K]) unsharedTable() inout { return *cast(inout(V[K])*) } ``` Thanks, that worked! Feels like programming in C, though. If I could figure out how to initialize the AA explicitly, I could also remove the ref here. If I just remove the ref, the AA is always null. If I try to initialize it in the constructor, I get this: src\syncaa.d(11,5): Error: `_d_monitorenter` cannot be interpreted at compile time, because it has no available source code No idea why, it seems to happen if I try to use the AA in the constructor at all. Even when I just do `data_.remove(K.init);` I also tried DMD 2.101.0-rc.1, using the new `new V[K]` syntax, same error there.
Re: aa.keys, synchronized and shared
With allocation: ``` synchronized final class SyncAA(K, V) { V opIndex(K key) { return sharedTable[key]; } V opIndexAssign(V value, K key) { return sharedTable[key]=value; } const(K[]) keys() const { return unsharedTable.keys; } void remove(K key) { sharedTable.remove(key); } V get(K key, lazy V defaultValue=V.init) { auto p = key in sharedTable; return p ? *p : defaultValue; } private: V[K] sharedTable; ref inout(V[K]) unsharedTable() inout { return *cast(inout(V[K])*) } } shared SyncAA!(string,string) saa; void f() { saa=new shared SyncAA!(string,string); saa.keys(); saa["12"]="34"; saa.remove("12"); } ```
Re: aa.keys, synchronized and shared
Try this: ``` synchronized final class SyncAA(K, V) { V opIndex(K key) { return sharedTable[key]; } V opIndexAssign(V value, K key) { return sharedTable[key]=value; } const(K[]) keys() const { return unsharedTable.keys; } void remove(K key) { sharedTable.remove(key); } V get(K key, lazy V defaultValue=V.init) { auto p = key in sharedTable; return p ? *p : defaultValue; } private: V[K] sharedTable; ref inout(V[K]) unsharedTable() inout { return *cast(inout(V[K])*) } } void f(shared SyncAA!(string,string) a) { a.keys(); a["12"]="34"; a.remove("12"); } ```
Re: aa.keys, synchronized and shared
On Friday, 11 November 2022 at 01:09:54 UTC, torhu wrote: On Thursday, 10 November 2022 at 21:55:26 UTC, torhu wrote: I'm trying to make a more thread-safe wrapper for AA's: ``` synchronized final class SyncAA(K, V) /// I chose to fix this by just using `synchronized (this)` inside each method instead, for now. Still interested in cleaner solutions, but I guess synchronized/shared is a bit of a rabbit hole... That's about what I ended up with, and just declaring my references __gshared. I don't know what's going on with shared/synchronized but it sounds like it's unfinished and people can't agree on what they're actually supposed to mean. __gshared, it just works. Previous thread: [synchronized/shared associative array .require error](https://forum.dlang.org/post/hcbrgpmdufjgjtxtu...@forum.dlang.org) Also: [synchronized - shared but actually useful](https://forum.dlang.org/thread/drrlgymevccozrqms...@forum.dlang.org) ```d class SyncTable(KEY, VAL) { private VAL[KEY] table; auto opIndexAssign(VAL value, KEY key) { synchronized(this) { return table[key] = value; } } int opApply(int delegate(ref KEY, ref VAL) dg) { synchronized(this) { foreach (key, val; table) { if (dg(key, val)) return 1; } return 0; } } auto opBinaryRight(string op)(KEY key) if (op == "in") { synchronized(this) { return key in table; } } auto opDispatch(string s, SA...)(SA sargs) { synchronized(this) { static if (SA.length == 0) { mixin(format("return table.%s;", s)); } else { mixin(format("return table.%s(%s);", s, sargs.stringof[6 .. $-1])); // tuple(_param_0) } } } } ``` With synchronized on the class, I had to do something like: ```d synchronized class SyncTable(KEY, VAL) { // Anything that mutates must reassign unshared back to table! auto opIndexAssign(VAL value, KEY key) { auto unshared = cast(T) table; unshared[key] = value; table = cast(shared) unshared; return value; } auto require(KEY key) { auto unshared = cast(T) table; auto r = unshared.require(key); table = cast(shared) unshared; return r; } /* ... */ } ``` and it just doesn't feel right. For mutexes without synchronized, there's also: ```d struct Lock { private shared Mutex _mtx; this(shared Mutex mtx) { _mtx = mtx; _mtx.lock(); } this(this) @disable; ~this() { if (_mtx) _mtx.unlock(); _mtx = null; } } class SyncTable(KEY, VAL) { private VAL[KEY] table; shared Mutex mtx; this() { mtx = new shared Mutex; } auto opIndexAssign(VAL value, KEY key) { auto lock = Lock(mtx); return table[key] = value; } /* ... */ } ```
Re: aa.keys, synchronized and shared
On Thursday, 10 November 2022 at 21:55:26 UTC, torhu wrote: I'm trying to make a more thread-safe wrapper for AA's: ``` synchronized final class SyncAA(K, V) /// I chose to fix this by just using `synchronized (this)` inside each method instead, for now. Still interested in cleaner solutions, but I guess synchronized/shared is a bit of a rabbit hole...