Capturing by value in the thread
Steven Schveighoffer
schveiguy at gmail.com
Sat Oct 19 03:35:26 UTC 2024
On Friday, 18 October 2024 at 12:07:24 UTC, Kadir Erdem Demir
wrote:
> It seems [=] functionality C++ does not exist in D.
No, D does not have this functionality.
> By using a helper function I made that example work.
>
> ```d
>
> import std.stdio;
>
> auto localFoo(int x) {
> return (){ return x;};
> }
>
> void main() {
> int x = 10;
>
> auto lambda = (int capturedX = x) {
> writeln("Captured reference : ", capturedX);
> };
>
> auto localFoo = localFoo(x);
>
> x = 20;
> writeln(localFoo());// Outputs: Captured value: 10 --> That
> is what I need
> lambda(); // Outputs: 20
>
> }
>
> ```
D captures all closures via allocation onto the heap. Using
`localFoo` is the correct way to do this.
For nested functions, it has a reference to the outer stack
frame, this is different.
But your example is even different, a default parameter means
"pass this parameter if none is passed". So your call to
`lambda()` is treated as if you wrote `lambda(x)`. It's not
captured on definition, it's passed on usage.
>
> But when I trying the same technique on std.Thread it does not
> work. Always reference is being captured.
>
> ```d
>
>
> void InitCurrencies()
> {
> auto captureFuction(int index)
> {
> return (){
> auto localIndex = index;
> string[] currentChunk =
> ChunkedExchangePairNames(localIndex);
> writeln("Thread index: ", localIndex, " pairs:
> ", currentChunk.join(";"));
> foreach (exchangeName; currentChunk)
> Connect(exchangeName, WebSocketType.All);
> WebSocket.eventLoop(localLoopExited);
> };
> }
>
> for(int i = 0; i < m_ThreadCount; i++)
> {
> auto work = captureFuction(i);
> auto worker = new Thread({
> work();
> });
> m_workerList ~= worker;
> }
>
> foreach(worker; m_workerList)
> {
> worker.start();
> }
> }
>
> ```
> writeln("Thread index: ", localIndex, " pairs: ",
> currentChunk.join(";"))
> Always prints the last value of my for loop.
In this case, you are passing in a local anonymous function which
uses the stack frame pointer to find the value stored at `work`.
This value gets changed each time through the loop.
What you need to do is simply pass the work function into the
thread:
```d
auto worker = new Thread(work);
```
This copies the lambda *by value* into the Thread, and then you
can change work, it won't affect that copy.
Note that it is a very long standing issue that closures are not
done based on the full scope of everything -- only the stack
frame of the function is used.
-Steve
More information about the Digitalmars-d-learn
mailing list