Thread overview
Capturing by value in the thread
Oct 18
Kagamin
Oct 19
mzfhhhh
October 18

It seems [=] functionality C++ does not exist in D.
By using a helper function I made that example work.


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.



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

October 18

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;
}
October 19

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.


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.



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:

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

October 19

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.