Background thread, async and GUI (dlangui)
frame
frame86 at live.com
Thu Jul 21 17:26:07 UTC 2022
On Thursday, 21 July 2022 at 13:27:49 UTC, Bagomot wrote:
> I had this question: how can I get the value from the `task`,
> like how I can get from the `spawnLinked`(`ownerTid.send` and
> `receive`)?
>
> I'm using a `taskPool` through `arr.parallel`, but it became
> necessary to collect the progress from all tasks into one
> variable.
>
> In this case, I can't use `spawnLinked` because the worker is
> mutable, I get the "Aliases to mutable thread-local data not
> allowed" error.
The module creators want you to prevent from non-threadsafe
actions. Merging into one variable can be such a non-threadsafe
action, but it has not to be.
For example, if you have an array of fixed length or an already
allocated one and each worker thread uses a fixed index to write
into this result array variable then this operation may be
threadsafe because each thread writes in different positions in
the memory and the variable itself doesn't change.
If you are depending to overwrite an value instead, the operation
is not considered threadsafe. For example just adding 1 + 2.
Adding a value to an associative array is also not thread safe
(it may re-allocate or re-index it's data)
We have basic tools to achieve this task. One is to lock actions
with a synchronized block so each thread need to wait the other
thread to complete before it can continue to execute the
particular code position - and the other one are atomic
operations that provide a better performance for simple
operations because they are lock-free.
Why it's needed to know this? Because you may run into situations
where have to deal with it, even the compiler keeps silent about.
https://dlang.org/spec/statement.html#synchronized-statement
```d
// parent:
int result;
// ...
// worker/parallel:
// each thread can only run this code if no other thread is
currently running this code section => the OS is locking, this
costs time
synchronized {
result += 1;
}
```
https://dlang.org/phobos/core_atomic.html#.atomicOp
Usage of `atomaticOp` is simple, eg.
```d
// parent:
shared int result;
// ...
// worker/parallel:
// lock free, D-runtime ensures for a threadsafe operation
atomicOp!"+="(result, 1);
```
Looking on `atomicOp` you will see it want you to use a `shared`
variable. And this is an easy way to make the compiler happy if
you have mutual data. If you know what you are doing (not making
thread unsafe-operations) then it's fine to just cast your data
to `shared` that now can be sent or received.
```d
tid.send(cast(shared)mutualData);
```
A better approach is always to avoid such things completely and
design your workflow to send and receive only simple data types
(or immutable ones, which is also fine).
> Also, I could make a new `Thread` for each task, but I think
> this is a bad idea. Also, I don't know how to send messages
> from child thread to parent thread.
The messagebox system from `std.concurrency` should also work
with parallelism tools, meaning inside a worker thread use
`std.concurrency.ownerTid` to get the parent Tid.
Looking for your task you might want to use a
`WorkerLocalStorage` solution instead, look at the example:
https://dlang.org/phobos/std_parallelism.html#.TaskPool.WorkerLocalStorage
More information about the Digitalmars-d-learn
mailing list