www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Capturing by value in the thread

reply Kadir Erdem Demir <kerdemdemir gmail.com> writes:
It seems [=] functionality C++ does not exist in D.
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

}

```	

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.


Is there a way to capture the value on anonymous function which 
is being passed t std.Thread
Oct 18
next sibling parent Kagamin <spam here.lot> writes:
this works for me
```
void aa()
{
	void delegate()[] items;

	auto captureFuction(int index)
	{
		return (){
			auto localIndex = index;
			writeln("index: ", localIndex);
		};
	}

	for(int i = 0; i < 10; i++)
	{
		auto work = captureFuction(i);
		items ~= work;
	}

	foreach(worker; items)
	{
		worker();
	}
}
int main()
{
     aa();
     return 0;
}
```
Oct 18
prev sibling next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
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
Oct 18
prev sibling parent mzfhhhh <mzfhhhh foxmail.com> writes:
On Friday, 18 October 2024 at 12:07:24 UTC, Kadir Erdem Demir 
wrote:
 It seems [=] functionality C++ does not exist in D.
 By using a helper function I made that example work.

 [...]
Because 'work' is captured, it is allocated on the heap. The loops are all assigning values to this 'work' in the heap. The values in front of 'work' are all overwritten, so after the thread runs, it prints the last value.
Oct 18