digitalmars.D.learn - aa.keys, synchronized and shared
- torhu (57/57) Nov 10 2022 I'm trying to make a more thread-safe wrapper for AA's:
- torhu (5/8) Nov 10 2022 I chose to fix this by just using `synchronized (this)` inside
- cc (91/100) Nov 10 2022 That's about what I ended up with, and just declaring my
- Kagamin (28/28) Nov 11 2022 Try this:
- torhu (13/22) Nov 11 2022 Thanks, that worked! Feels like programming in C, though. If I
- Kagamin (30/30) Nov 11 2022 With allocation:
I'm trying to make a more thread-safe wrapper for AA's:
```
synchronized final class SyncAA(K, V) ///
{
///
V opIndex(K key) { return data_[key]; }
///
V opIndexAssign(V value, K key) { return data_[key] = value; }
///
K[] keys() const { return data_.keys; }
///
void remove(K key) { data_.remove(key); }
/// There is no `in` operator, it would not be thread-safe.
V get(K key, lazy V defaultValue=V.init)
{
auto p = key in data_;
return p ? *p : defaultValue;
}
///
int opApply(scope int delegate(inout ref V) dg) const
{
int result = 0;
foreach (value; data_) {
result = dg(value);
if (result)
break;
}
return result;
}
///
int opApply(scope int delegate(K, inout ref V) dg) const
{
int result = 0;
foreach (key, value; data_) {
result = dg(key, value);
if (result)
break;
}
return result;
}
private:
V[K] data_;
}
```
In another file:
`__gshared serverListCache = new SyncAA!(string, ServerList);`
I'm using `keys` in a regular function, this is the error i get:
C:\prog\dmd\windows\bin\..\..\src\druntime\import\object.d(3245,36): Error:
cannot implicitly convert expression `aa` of type
`shared(const(ServerList[string]))` to `const(shared(ServerList)[string])`
src\syncaa.d(17,36): Error: template instance
`object.keys!(shared(const(ServerList[string])),
shared(const(ServerList)), string)` error instantiating
src\serveractions.d(45,33): instantiated from here:
`SyncAA!(string, ServerList)`
src\serveractions.d(50,17): Error: `shared` `const` method
`syncaa.SyncAA!(string, ServerList).SyncAA.keys` is not callable
using a non-shared mutable object
Error C:\prog\dmd\windows\bin\dmd.exe failed with exit code 1.
Nov 10 2022
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...
Nov 10 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: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; } /* ... */ } ```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...
Nov 10 2022
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])*)&sharedTable;
}
}
void f(shared SyncAA!(string,string) a)
{
a.keys();
a["12"]="34";
a.remove("12");
}
```
Nov 11 2022
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])*)&sharedTable; } ```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.
Nov 11 2022
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");
}
```
Nov 13 2022
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.
Nov 14 2022
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])*)&sharedTable;
}
}
shared SyncAA!(string,string) saa;
void f()
{
saa=new shared SyncAA!(string,string);
saa.keys();
saa["12"]="34";
saa.remove("12");
}
```
Nov 11 2022









cc <cc nevernet.com> 