Re: Synchronisation help

2024-01-01 Thread Steven Schveighoffer via Digitalmars-d-learn

On Monday, 1 January 2024 at 15:48:16 UTC, Anonymouse wrote:
What is the common solution here? Do I add a module-level 
`Object thing` and move everything accessing the AA into 
`synchronized(.thing)` statements? Or maybe add a `shared 
static` something to `Foo` and synchronise with 
`synchronize(Foo.thing)`?


Yeah, and the thing should be a `Mutex` object. A `Mutex` object 
uses it's underlying mutex primitive as its monitor. This also 
gives options for usage with methods as well as `synchronized` 
statements.


Just make sure you mark it `__gshared` or `shared` so all threads 
see it.


-Steve


Re: Synchronisation help

2024-01-01 Thread Jonathan M Davis via Digitalmars-d-learn
On Monday, January 1, 2024 8:48:16 AM MST Anonymouse via Digitalmars-d-learn 
wrote:
> I have a `shared string[int]` AA that I access from two different
> threads. The function I spawn to start the second thread takes
> the AA as an argument.
>
> ```d
> class Foo
> {
>  shared string[int] bucket;
>  Tid worker;
> }
>
> void workerFn(shared string[int] bucket)
> {
>  while (true)
>  {
>  // occasionally reads, occasionally modifies bucket
>  }
> }
>
> void main()
> {
>  auto foo = new Foo;
>  foo.bucket[0] = string.init;
>  foo.bucket.remove(0);
>  foo.worker = spawn(, foo.bucket);
>
>  while (true)
>  {
>  // occasionally reads, occasionally modifies bucket
>  }
> }
> ```
>
> (`run.dlang.io` shortening seems broken again, but I made a
> [gist](https://gist.github.com/zorael/17b042c424cfea5ebb5f1f3120f983f4) of a
> more complete example.)
>
> Reading the specs on `synchronized` statements, it seems I need
> to provide an `Object` to base synchronisation on when two
> *different* places in the code needs synchronising, whereas if
> it's in the same place an expressionless `synchronize { }` will
> do.
>
> The worker function can't see `Foo foo` inside `main`, so it
> can't share synchronisation on that.
>
> What is the common solution here? Do I add a module-level `Object
> thing` and move everything accessing the AA into
> `synchronized(.thing)` statements? Or maybe add a `shared static`
> something to `Foo` and synchronise with `synchronize(Foo.thing)`?

In general, I would advise against using synchronized statements. They
really don't add anything, particularly since in many cases, you need access
to more complex thread-synchronization facilities anyway (e.g. condition
variables). Really, synchronized statements are just a Java-ism that D got
fairly early on that were arguably a mistake. So, I'd typically suggest that
folks just use Mutex from core.sync.mutex directly (though you can certainly
use them if you don't need to do anything more complex).

https://dlang.org/phobos/core_sync_mutex.html

If you're using synchronized statements, you're essentially just using
syntax which does that underneath the hood without providing you the
functionality to use stuff like Condition from core.sync.condition.

https://dlang.org/phobos/core_sync_condition.html

However, regardless of whether you use synchronized or use Mutex directly,
what you need to do is to have an object that functions as a mutex to
protect the shared data, locking it whenever you access it so that only one
thread can access it at a time.

The best place to put that mutex varies depending on what your code is
doing. A shared static variable could make sense, but it's often the case
that you would put the mutex inside the class or struct that contains the
data that's shared across threads. Or if you don't have a type that's
intended to encompass what you're doing with the shared data, then it often
makes sense to create one to hold the shared data so that the code that's
using it doesn't have to deal with the synchronization mechanisms but rather
all of that mess is contained entirely within the class or struct that
you're passing around. But even if you don't want to encapsulate it all
within a struct or class, simply creating one to hold both the shared data
and the mutex makes it so that they'll be together wherever you're passing
them around, making it easy for the code using the AA to access the mutex.

However, because you're not supposed to actually be mutating data while it's
shared (and the compiler largely prevents you from doing so), what you
generally need to do to operate on shared data is to lock the mutex that
protects it, cast away shared so that you can operate on the data, do
whatever it is that you need to do with the now thread-local data, make sure
that no thread-local references to the data exist any longer, and then lock
the mutex again. And to do that cleanly, it's often nice to create a struct
or class with shared member functions which takes care of all of that for
you so that that particular dance is encapsulated rather than having to deal
with any code that has access to that shared data having to deal with the
synchronization correctly.

Given that you already have a class called Foo which contains the AA, I
would say that the most obvious thing to do would be to just pass a shared
Foo across threads rather than pass the AA from inside Foo. Then you can
either put a mutex in Foo that then naturally gets passed along with the AA,
or you just use the class itself as a mutex - e.g. synchronized(this) {}
IIRC - since classes unfortunately have a mutex built into them to make
synchronized member functions work (which is useful when you want to use
synchronized functions but causes unnecessary bloat for most classes). And
if it makes sense to lock the mutex during entire function calls, you can
just make the member function synchronized rather than having 

Synchronisation help

2024-01-01 Thread Anonymouse via Digitalmars-d-learn
I have a `shared string[int]` AA that I access from two different 
threads. The function I spawn to start the second thread takes 
the AA as an argument.


```d
class Foo
{
shared string[int] bucket;
Tid worker;
}

void workerFn(shared string[int] bucket)
{
while (true)
{
// occasionally reads, occasionally modifies bucket
}
}

void main()
{
auto foo = new Foo;
foo.bucket[0] = string.init;
foo.bucket.remove(0);
foo.worker = spawn(, foo.bucket);

while (true)
{
// occasionally reads, occasionally modifies bucket
}
}
```

(`run.dlang.io` shortening seems broken again, but I made a 
[gist](https://gist.github.com/zorael/17b042c424cfea5ebb5f1f3120f983f4) of a more complete example.)


Reading the specs on `synchronized` statements, it seems I need 
to provide an `Object` to base synchronisation on when two 
*different* places in the code needs synchronising, whereas if 
it's in the same place an expressionless `synchronize { }` will 
do.


The worker function can't see `Foo foo` inside `main`, so it 
can't share synchronisation on that.


What is the common solution here? Do I add a module-level `Object 
thing` and move everything accessing the AA into 
`synchronized(.thing)` statements? Or maybe add a `shared static` 
something to `Foo` and synchronise with `synchronize(Foo.thing)`?