aa.keys, synchronized and shared

cc cc at nevernet.com
Fri Nov 11 05:25:36 UTC 2022


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/hcbrgpmdufjgjtxtuoju@forum.dlang.org)
Also: [synchronized - shared but actually 
useful](https://forum.dlang.org/thread/drrlgymevccozrqmsxle@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;
	}
	/* ... */
}
```



More information about the Digitalmars-d-learn mailing list