www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 16324] New: std.parallelism taskPool does not terminate

https://issues.dlang.org/show_bug.cgi?id=16324

          Issue ID: 16324
           Summary: std.parallelism taskPool does not terminate daemon
                    threads
           Product: D
           Version: D2
          Hardware: x86_64
                OS: Linux
            Status: NEW
          Severity: major
          Priority: P1
         Component: phobos
          Assignee: nobody puremagic.com
          Reporter: moritz ucworks.org

This program will never exit (it should exit):

import std.parallelism;

void main()
{
    taskPool;
    taskPool.put(task({ while (true) {} }));
}

This seems to happen because of the following destructor (see
https://github.com/dlang/phobos/blob/c74537000c96f92c9f664f0504d9be8b7250d309/std/parallelism.d#L988):

// Kill daemon threads.
shared static ~this()
{
    auto allThreads = Thread.getAll();

    foreach (thread; allThreads)
    {
        auto pthread = cast(ParallelismThread) thread;
        if (pthread is null) continue;
        auto pool = pthread.pool;
        if (!pool.isDaemon) continue;
        pool.stop();
        pthread.join();
    }
}

The above does not actually kill a daemon thread (which is not something we
should take care of, but the OS), it tries to join it, i.e. wait for it to
complete on its own (which defeats the purpose of having a thread be a daemon).
I consider this a major issue, because it blocks me from using it with
synchronous file IO (threadpool + synchronous file IO is a common use case
under Linux), where an uncompleted synchronous file operation in a daemon
thread must not block program termination.

To see the differences, compare the following three programs:

This program will never exit (because we try to join the thread):

import core.thread;

void main()
{
    auto t = new Thread({ while (true) {} });
    t.start();
    t.isDaemon = true;
    t.join();
}

This program will exit (as it should, the OS takes care of killing the daemon
thread):

import core.thread;

void main()
{
    auto t = new Thread({ while (true) {} });
    t.start();
    t.isDaemon = true;
}

This program will never exit (as the created thread is not a daemon thread and
its execution blocks program termination):

import core.thread;

void main()
{
    auto t = new Thread({ while (true) {} });
    t.start();
}

The destructor quoted above needs to be fixed so that it does not try to join
daemon threads.

--
Jul 27 2016