On 17-Dec-2013 07:29 -0800, Michael Schutte wrote:
Every month we are getting an error from SNDDST saying that it cannot
be ran in jobs with multiple threads. I get that this command cannot
run with multiple threads. But I am curious on why we are getting
multiple threads in an interactive session.

The /system/ can create additional threads, system threads, irrespective the Allow Multiple Threads (ALWMLTTHD) attribute for the job. Only user threads are prevented from being created in the job contrary to the threading limitations.

The program trying to use this command is vendor code. All of their
code is written in RPG3 and CLP running in the default activation
group. We now own the code and as we make changes to the code, we
convert to RPGLE. We have created service programs, some with named
activation groups, others with named activation groups.

Some with named ActGrp and some with ¿caller? or ¿new?

We have also introduced SQLRPGLE into some programs (FYI, when we
make changes to the vendor code, we move to a new library higher in
the LIBL, we leave the original code alone, just our decision to do
that). Side note, all programs called interactively is called by a
menu program written in RPG3 by the same vendor, as we convert the
called programs from RPG3 to RPGLE we sometimes add H-SPEC
actgrp(*CALLER) other times we do not. When using *CALLER, it's my
understanding that the program run in the default activation group.
Not sure if this matters to anyone trying help me with this

In the *CALLER scenario for an SQLRPGLE called from the DftActGrp, a reusable query will not close [Close SQL Cursor (CLSSQLCSR) parameter], so the associated threads can remain active, awaiting more work to complete the query activity. Similarly any open\active query implemented with multiple threads that has not been full-closed could presumably cause the same issue.

Depending on the origin for the multiple threads, if by query activity, the Change Query Attributes (CHGQRYA) to assign a Parallel Processing Degree (DEGREE) of *NONE can suppress the use of multiple threads for a query. If however the threads are due to User Defined Function (UDF) invocation versus either I/O parallel or SMP processing, then the change to the Query Attributes [AFaIK] does not apply.

I've been reading articles on the web about multithreading (new
concept to me). I remember once reading that to start a new thread,
the program has to specifically call the spawn routine. I'm certain
that none of us at this shop has done this in any programs (lack of
understanding being the biggest hurdle). I've also read that Only
batch immediate jobs and prestart jobs provide multithread-capable
support here:

Warning: The above link froze my browsers for several minutes
The above link is further described by the following:

v4r5 InfoCenter -> Programming -> Programming Support -> Multithreaded Applications
_i Multithreaded applications i_
_What is a thread_?
_Thread basics_:
_Programming with threads_:
_Code snippets that show how to use threads_:

With that information, I found the effective equivalent v7r1 link is:
wherein there is a link to:
_PDF file for Multithreaded applications_

The statement about the spawn is that "The spawn() API is the only programming method that can start a batch immediate or prestart job that is capable of supporting multiple threads." However earlier a statement notes that "In the i5/OS® kernel threads support, only a subset of the supported job types can create threads. Interactive and communication jobs do not provide multithread-capable support." And that the "OS examines all job types except communications jobs and interactive jobs for the ALWMLTTHD parameter." So while the spawn() API may effect a multithreaded job type of BCI or PJ, that does not suggest other job types are precluded from multi-threading per use of ALWMLTTHD; i.e. allowing multiple threads, beyond just system-initiated /system threads/. For example even a batch job started with Submit Job (SBMJOB) using either the Allow Multiple Threads (ALWNLTTHD) parameter to *YES, or instead deferring to a Job Description (*JOBD) set to allow threads, will start a multithreaded job type of BCH; the threads within the job may not be started with the spawn() API, but other thread APIs such as pthread_create() (a POSIX thread API). So anyhow, hopefully to clarify:

_Running threaded programs_
"When you run a threaded program, the job that runs a threaded program must be specially initialized by the system to support threads. Currently, several mechanisms allow you to start a job that is capable of creating multiple kernel threads:

But that's documentation for V4R5, we are currently on V7R1. But if
this is still the case why are our interactive jobs spawning multiple

Again, most likely system-initiated threads; i.e. system-threads that are allowed to disregard the ALWMLTTHD(*NO) specification of an interactive job.

Unfortunately, I do not have any job logs to include in this email,
however as I recall the error was message CPFA0A8 "Operation not
allowed in a job running multiple threads."

When the error occurs, the output from WRKJOB OPTION(*ALL) OUTPUT(*PRINT) SLTTHD(*ALL) I expect should produce output that includes both the *THREAD information and the thread stacks. With the details from the threads, perhaps what created those other threads will be obvious. There is however an allusion to a potential restriction for the above WRKJOB invocation, so the OPTION(*PGMSTK) might have to be specified; i.e. the docs suggest a [but not what specific] failure, if OPTION(*ALL) is invoked "in a job that allows multiple threads" versus being invoked in a job that _has_ multiple threads. Another more likely issue, is that the system threads for the Query Engine will sit idle for an open query not actively running, such that the threads have no active stack, pending receipt of further work.

The Dump Job (DMPJOB) with Job Threads (JOBTHD) parameter as *YES asking for thread information might be required to get the necessary information, because the threads may have no active stack. While I am not aware of any system vs user nor any identification of what initiated the thread visible from Work With Job (WRKJOB) output, perhaps something in the DMPJOB gives more details; e.g.:

A job trace [Start Job Trace (STRTRC)] started at the point of the failure is potentially helpful, but the tracing must catch and include in its output, future activity of those other threads, even if only the termination of the threads.

I also came across this website. Multithreaded programs in Java
"The Java™ runtime environment is inherently multithreaded."

While essentially true, though for a different reason, the reference to MQM docs is probably not the best reference for the issue at hand. More appropriately the following doc reference; see my emphasis with asterisks for the JVM:
IBM i 7.1 Information Center -> Programming -> Multithreaded applications -> Language access and threads
_i Threads considerations for Java language i_
"Java™ threads operate on top of the i5/OS® kernel threads model using the java.lang.Thread class. Each Java thread is one of the many tasks that run in the process.

You can do all of the activities that are listed in the Threads Management section.

The Java virtual machine (JVM) *always creates several threads* to perform services such as Java garbage collection. The system uses these threads; applications should not use them.

You can use native methods to access system functions that are not available in Java. Native methods are not *PGM objects. They are procedures that are exported from Integrated Language Environment® (ILE) service programs (*SRVPGM). These *native methods always run* *in multithreaded processes*; therefore, they must be threadsafe. The ILE COBOL, RPG IV, CL, C, and C++ compilers are threadsafe.

So I can see where this could be our issue. Some new emails that we
send out are being sent using RPGMAIL. RPGMAIL uses Java. So if the
user did something to send out an email, I can see this being our
culprit. But there's only one program that I recall that gets sent
using RPGMAIL and I know that it hasn't been sent because I am copied
on it. All other RPGMAIL emails are sent from batch job that are
submitted from the Job scheduler and therefore wouldn't have an
effect on any one interactive session.

Perhaps then, JAVA has been excluded.?

This doesn't happen for all users, just a select few. The ones that
get the error are different from month to month.

Maybe review the PRTSQLINF of the SQLRPGLE [service] programs to look for UDF utilization and any parallel implementations.

The boss started asking why has this just started. The truth is we
really don't know if it just now started to happen as users used to
ignore these kind of messages. As far as they were concerned the
program completed successfully because accounts receivables had
generated an invoice (but no email was sent).

Perhaps changing the code in reaction to the failure of the SNDDST to do something that the user can not merely ignore; performing something that [unlike the SNDDST] does not fail when multiple threads are active in the process.

Others, in discussions found on the web for a matching failure, suggest using something other than SNDDST to avoid the restriction; e.g. either use a command [or API\program-call] to effect the send of the message\mail that is not restricted to a process with only the one\initial thread, or run the SNDDST in another process such as in a submitted job [per SBMJOB] or off-load to a job awaiting an entry on a queue that notifies of the SNDDST work to be done.

But if this is new what could be spawning the multiple threads? Is it
the SQL, Activation Groups, or is the Java?

I am betting some SQL, and the ActGrp choice may play a role, due to the effect on the [lack of] closure of cursors. Possibly the query implementation for certain\specific inquiries is done using parallel processing, such that only those jobs later becoming the /incident/ with the failing symptom; or perhaps they always implement with parallel, but only sometimes does a user end up taking that particular path through the code.

The open-files list [WRKJOB OPTION(*OPNF)] might help to infer some query activity, and the activation group for the open. If the job remains active with multiple threads, and the user can be allowed to issue a SNDDST for testing, then servicing [STRSRVJOB] and debug [STRDBG] could be issued against the job. After verifying the SNDDST still fails, reclaim each of the activations [RCLACTGRP] and test again if the SNDDST still fails [and\or the WRKJOB OPTION(*THREAD) to see if the threads went away]; a SQL cursor getting closed as a side effect will appear in the joblog as a query debug message. That could help to find the program\query responsible for the extra threads.

This thread ...

Follow On AppleNews
Return to Archive home page | Return to MIDRANGE.COM home page

This mailing list archive is Copyright 1997-2020 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].