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;
}
/* ... */
}
```