From 240d6b1f0eb7f4c11b054f1424b11b2404ca03ab Mon Sep 17 00:00:00 2001 From: jlangch Date: Fri, 29 Mar 2024 18:35:41 +0100 Subject: [PATCH] added thread type support to the function `thread` to allow spawning daemon or user threads --- ChangeLog.md | 2 ++ .../impl/functions/ConcurrencyFunctions.java | 26 ++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 41d44cd69..82e65bdae 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -11,6 +11,8 @@ All notable changes to this project will be documented in this file. ### Added - function `io/file-normalize-utf` +- thread type support to the function `thread` to allow spawning daemon or user + threads diff --git a/src/main/java/com/github/jlangch/venice/impl/functions/ConcurrencyFunctions.java b/src/main/java/com/github/jlangch/venice/impl/functions/ConcurrencyFunctions.java index 3fd1e7899..46abbf78a 100644 --- a/src/main/java/com/github/jlangch/venice/impl/functions/ConcurrencyFunctions.java +++ b/src/main/java/com/github/jlangch/venice/impl/functions/ConcurrencyFunctions.java @@ -2541,13 +2541,21 @@ public VncVal apply(final VncList args) { VncFunction .meta() .arglists( - "(thread f)", "(thread f name)") + "(thread f)", + "(thread f name)", + "(thread f name type)") .doc( "Executes the function f in another thread, returning immediately to the " + "calling thread. Returns a `promise` which will receive the result of " + "calling the function f when completed. Optionally a name can be assigned " + "to the spawned thread." + "\n\n" + + "The thread can be given a name by passing the *name* argument. By default " + + "the thread names is set to \"venice-thread\". For each thread spawned on " + + "a name the thread's name will be suffixed with an incrementing index starting " + + "from 1.\n\n" + + "The thread type *daemon* or *user* can be controlled by the *type* argument " + + "that must be one of {:daemon, :user}. By default a daemon thread is spawned.\n\n" + "*Note:* Each call to `thread` creates a new expensive system thread. " + "Consider to use futures or promises that use an *ExecutorService* to " + "deal efficiently with threads.") @@ -2555,6 +2563,7 @@ public VncVal apply(final VncList args) { "@(thread #(do (sleep 100) 1))", "@(thread #(do (sleep 100) (thread-name)))", "@(thread #(do (sleep 100) (thread-name)) \"job\")", + "@(thread #(do (sleep 100) (thread-name)) \"job\" :user)", ";; consumer / producer \n" + "(do \n" + " (defn produce [q] \n" + @@ -2571,15 +2580,25 @@ public VncVal apply(final VncList args) { ) { @Override public VncVal apply(final VncList args) { - ArityExceptions.assertArity(this, args, 1, 2); + ArityExceptions.assertArity(this, args, 1, 2, 3); final VncFunction fn = Coerce.toVncFunction(args.first()); fn.sandboxFunctionCallValidation(); - final String name = args.size() == 2 + final String name = args.size() >= 2 ? Coerce.toVncString(args.second()).getValue() : null; + final VncKeyword type = args.size() == 3 + ? Coerce.toVncKeyword(args.third()) + : new VncKeyword("daemon"); + + if (!(type.hasValue("daemon") || type.hasValue("user"))) { + throw new VncException(String.format( + "Function 'thread' requires type to be one of {:daemon, :user}. %s is invalid", + type.getValue())); + } + final CallFrame[] cf = new CallFrame[] { new CallFrame(this, args), new CallFrame(fn) }; @@ -2601,6 +2620,7 @@ public VncVal apply(final VncList args) { final Thread th = GlobalThreadFactory.newThread(name, taskWrapper); + th.setDaemon(type.hasValue("daemon")); th.start(); return new VncJavaObject(result);