www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Capture context surrounding delegate

reply Python <python python.com> writes:
Too much code below, but I cannot reduce it more. The issue is in 
the main function, I want to pass a delegate to a thread with a 
captured value from the surrounding context. At least this was my 
expectation, the delegate should capture any stack value.

Am I doing something wrong?

(please ignore lock abuse, I know that are better ways to do it, 
let's concentrate on problem at hand).

```d
import std.stdio;
import core.thread;

void main()
{
     for (int i = 0; i < 100; ++i)
     {
         auto captured = i;
         //how do i capture i?
         //it's always 99 (or near when first threads are spawned 
before
         //for cycle ends)
         ThreadPool.enqueue(() {
             writefln("Item: %d on thread %d, running %d threads", 
captured, Thread.getThis.id, ThreadPool.threads);
         });
     }

     writeln("all enqueued");
     getchar();
}

struct ThreadPool
{
     private static __gshared _queue_lock = new Object();
     private static __gshared _thread_lock = new Object();
     private static __gshared const(void delegate())[] _queue;
     private static __gshared int threads;

     private static __gshared int _minThreads = 1;
     private static __gshared int _maxThreads = 10;

     private static auto dequeue()
     {
         synchronized(_queue_lock)
         {
             if (_queue.length > 0)
             {
                 auto item = _queue[0];
                 _queue = _queue[1 .. $];
                 return item;
             }
             else
             {
                 return null;
             }
         }
     }

     static void enqueue(void delegate() item)
     {
         synchronized(_queue_lock)
         {
             _queue ~= item;
         }
         resizeIfNeeded();
     }

     private static void resizeIfNeeded()
     {
         synchronized(_thread_lock)
         {
             if (threads < _maxThreads)
             {
                 synchronized(_queue_lock)
                 {
                     if (_queue.length > 0)
                     {
                         new Thread(&run).start();
                         ++threads;
                     }
                 }
             }
         }
     }

     private static void run()
     {
         while (true)
         {
             auto item = dequeue();
             if (item !is null)
             {
                 item();
             }
             else
             {
                 synchronized(_thread_lock)
                 {
                     if (threads > _minThreads)
                     {
                         --threads;
                         break;
                     }
                 }
             }
         }
     }
}



```
May 09
next sibling parent Nick Treleaven <nick geany.org> writes:
On Saturday, 10 May 2025 at 04:52:15 UTC, Python wrote:
     for (int i = 0; i < 100; ++i)
     {
         auto captured = i;
         //how do i capture i?
         //it's always 99 (or near when first threads are 
 spawned before
         //for cycle ends)
         ThreadPool.enqueue(() {
             writefln("Item: %d on thread %d, running %d 
 threads", captured, Thread.getThis.id, ThreadPool.threads);
         });
     }
This is a known issue with capturing variables scoped in a loop: https://issues.dlang.org/show_bug.cgi?id=21929#c10
May 10
prev sibling next sibling parent reply Tim <tim.dlang t-online.de> writes:
On Saturday, 10 May 2025 at 04:52:15 UTC, Python wrote:
 Too much code below, but I cannot reduce it more. The issue is 
 in the main function, I want to pass a delegate to a thread 
 with a captured value from the surrounding context. At least 
 this was my expectation, the delegate should capture any stack 
 value.

 Am I doing something wrong?
This is a known issue. See e.g. https://github.com/dlang/dmd/issues/18108 A workaround is to put the loop body in an additional function, which is directly called: ```d for (int i = 0; i < 100; ++i) { (){ auto captured = i; ThreadPool.enqueue(() { writefln("Item: %d on thread %d, running %d threads", captured, Thread.getThis.id, ThreadPool.threads); }); }(); } ```
May 10
parent Python <python python.com> writes:
On Saturday, 10 May 2025 at 11:35:41 UTC, Tim wrote:
 This is a known issue. See e.g. 
 https://github.com/dlang/dmd/issues/18108
Wow, the original issue is 17 years old. https://issues.dlang.org/show_bug.cgi?id=2043 At least I know that not my threading stuff is causing this. Thanks.
May 10
prev sibling parent reply Justin Allen Parrott <erartqr gmail.com> writes:
On Saturday, 10 May 2025 at 04:52:15 UTC, Python wrote:
     getchar();
I don’t like this
May 12
parent reply Python <python python.com> writes:
On Monday, 12 May 2025 at 08:35:02 UTC, Justin Allen Parrott 
wrote:
 On Saturday, 10 May 2025 at 04:52:15 UTC, Python wrote:
     getchar();
I don’t like this
Poor man's tool to keep my threads running.
May 12
parent Justin Allen Parrott <erartqr gmail.com> writes:
On Monday, 12 May 2025 at 14:10:41 UTC, Python wrote:
 On Monday, 12 May 2025 at 08:35:02 UTC, Justin Allen Parrott 
 wrote:
 On Saturday, 10 May 2025 at 04:52:15 UTC, Python wrote:
     getchar();
I don’t like this
Poor man's tool to keep my threads running.
Thread-wait or join
May 12