Thread overview
Capturing by value in the thread
3 days ago
Kagamin
3 days ago
mzfhhhh
4 days ago

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

3 days ago

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;
}
3 days ago

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

3 days ago

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.