man-pages/man3/pthread_create.3.html
2021-03-31 01:06:50 +01:00

558 lines
20 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML><HEAD><TITLE>Man page of PTHREAD_CREATE</TITLE>
</HEAD><BODY>
<H1>PTHREAD_CREATE</H1>
Section: Linux Programmer's Manual (3)<BR>Updated: 2018-04-30<BR><A HREF="#index">Index</A>
<A HREF="/cgi-bin/man/man2html">Return to Main Contents</A><HR>
<A NAME="lbAB">&nbsp;</A>
<H2>NAME</H2>
pthread_create - create a new thread
<A NAME="lbAC">&nbsp;</A>
<H2>SYNOPSIS</H2>
<PRE>
<B>#include &lt;<A HREF="file:///usr/include/pthread.h">pthread.h</A>&gt;</B>
<B>int pthread_create(pthread_t *</B><I>thread</I><B>, const pthread_attr_t *</B><I>attr</I><B>,</B>
<B> void *(*</B><I>start_routine</I><B>) (void *), void *</B><I>arg</I><B>);</B>
</PRE>
<P>
Compile and link with <I>-pthread</I>.
<A NAME="lbAD">&nbsp;</A>
<H2>DESCRIPTION</H2>
The
<B>pthread_create</B>()
function starts a new thread in the calling process.
The new thread starts execution by invoking
<I>start_routine</I>();
<I>arg</I>
is passed as the sole argument of
<I>start_routine</I>().
<P>
The new thread terminates in one of the following ways:
<DL COMPACT>
<DT id="1">*<DD>
It calls
<B><A HREF="/cgi-bin/man/man2html?3+pthread_exit">pthread_exit</A></B>(3),
specifying an exit status value that is available to another thread
in the same process that calls
<B><A HREF="/cgi-bin/man/man2html?3+pthread_join">pthread_join</A></B>(3).
<DT id="2">*<DD>
It returns from
<I>start_routine</I>().
This is equivalent to calling
<B><A HREF="/cgi-bin/man/man2html?3+pthread_exit">pthread_exit</A></B>(3)
with the value supplied in the
<I>return</I>
statement.
<DT id="3">*<DD>
It is canceled (see
<B><A HREF="/cgi-bin/man/man2html?3+pthread_cancel">pthread_cancel</A></B>(3)).
<DT id="4">*<DD>
Any of the threads in the process calls
<B><A HREF="/cgi-bin/man/man2html?3+exit">exit</A></B>(3),
or the main thread performs a return from
<I>main</I>().
This causes the termination of all threads in the process.
</DL>
<P>
The
<I>attr</I>
argument points to a
<I>pthread_attr_t</I>
structure whose contents are used at thread creation time to
determine attributes for the new thread;
this structure is initialized using
<B><A HREF="/cgi-bin/man/man2html?3+pthread_attr_init">pthread_attr_init</A></B>(3)
and related functions.
If
<I>attr</I>
is NULL,
then the thread is created with default attributes.
<P>
Before returning, a successful call to
<B>pthread_create</B>()
stores the ID of the new thread in the buffer pointed to by
<I>thread</I>;
this identifier is used to refer to the thread
in subsequent calls to other pthreads functions.
<P>
The new thread inherits a copy of the creating thread's signal mask
(<B><A HREF="/cgi-bin/man/man2html?3+pthread_sigmask">pthread_sigmask</A></B>(3)).
The set of pending signals for the new thread is empty
(<B><A HREF="/cgi-bin/man/man2html?2+sigpending">sigpending</A></B>(2)).
The new thread does not inherit the creating thread's
alternate signal stack
(<B><A HREF="/cgi-bin/man/man2html?2+sigaltstack">sigaltstack</A></B>(2)).
<P>
The new thread inherits the calling thread's floating-point environment
(<B><A HREF="/cgi-bin/man/man2html?3+fenv">fenv</A></B>(3)).
<P>
The initial value of the new thread's CPU-time clock is 0
(see
<B><A HREF="/cgi-bin/man/man2html?3+pthread_getcpuclockid">pthread_getcpuclockid</A></B>(3)).
<A NAME="lbAE">&nbsp;</A>
<H3>Linux-specific details</H3>
The new thread inherits copies of the calling thread's capability sets
(see
<B><A HREF="/cgi-bin/man/man2html?7+capabilities">capabilities</A></B>(7))
and CPU affinity mask (see
<B><A HREF="/cgi-bin/man/man2html?2+sched_setaffinity">sched_setaffinity</A></B>(2)).
<A NAME="lbAF">&nbsp;</A>
<H2>RETURN VALUE</H2>
On success,
<B>pthread_create</B>()
returns 0;
on error, it returns an error number, and the contents of
<I>*thread</I>
are undefined.
<A NAME="lbAG">&nbsp;</A>
<H2>ERRORS</H2>
<DL COMPACT>
<DT id="5"><B>EAGAIN</B>
<DD>
Insufficient resources to create another thread.
<DT id="6"><B>EAGAIN</B>
<DD>
A system-imposed limit on the number of threads was encountered.
There are a number of limits that may trigger this error: the
<B>RLIMIT_NPROC</B>
soft resource limit (set via
<B><A HREF="/cgi-bin/man/man2html?2+setrlimit">setrlimit</A></B>(2)),
which limits the number of processes and threads for a real user ID,
was reached;
the kernel's system-wide limit on the number of processes and threads,
<I>/proc/sys/kernel/threads-max</I>,
was reached (see
<B><A HREF="/cgi-bin/man/man2html?5+proc">proc</A></B>(5));
or the maximum number of PIDs,
<I>/proc/sys/kernel/pid_max</I>,
was reached (see
<B><A HREF="/cgi-bin/man/man2html?5+proc">proc</A></B>(5)).
<DT id="7"><B>EINVAL</B>
<DD>
Invalid settings in
<I>attr</I>.
<DT id="8">
<DD>
<B>EPERM</B>
No permission to set the scheduling policy and parameters specified in
<I>attr</I>.
</DL>
<A NAME="lbAH">&nbsp;</A>
<H2>ATTRIBUTES</H2>
For an explanation of the terms used in this section, see
<B><A HREF="/cgi-bin/man/man2html?7+attributes">attributes</A></B>(7).
<TABLE BORDER>
<TR VALIGN=top><TD><B>Interface</B></TD><TD><B>Attribute</B></TD><TD><B>Value</B><BR></TD></TR>
<TR VALIGN=top><TD>
<B>pthread_create</B>()
</TD><TD>Thread safety</TD><TD>MT-Safe<BR></TD></TR>
</TABLE>
<P>
<A NAME="lbAI">&nbsp;</A>
<H2>CONFORMING TO</H2>
POSIX.1-2001, POSIX.1-2008.
<A NAME="lbAJ">&nbsp;</A>
<H2>NOTES</H2>
See
<B><A HREF="/cgi-bin/man/man2html?3+pthread_self">pthread_self</A></B>(3)
for further information on the thread ID returned in
<I>*thread</I>
by
<B>pthread_create</B>().
Unless real-time scheduling policies are being employed,
after a call to
<B>pthread_create</B>(),
it is indeterminate which thread---the caller or the new thread---will
next execute.
<P>
A thread may either be
<I>joinable</I>
or
<I>detached</I>.
If a thread is joinable, then another thread can call
<B><A HREF="/cgi-bin/man/man2html?3+pthread_join">pthread_join</A></B>(3)
to wait for the thread to terminate and fetch its exit status.
Only when a terminated joinable thread has been joined are
the last of its resources released back to the system.
When a detached thread terminates,
its resources are automatically released back to the system:
it is not possible to join with the thread in order to obtain
its exit status.
Making a thread detached is useful for some types of daemon threads
whose exit status the application does not need to care about.
By default, a new thread is created in a joinable state, unless
<I>attr</I>
was set to create the thread in a detached state (using
<B><A HREF="/cgi-bin/man/man2html?3+pthread_attr_setdetachstate">pthread_attr_setdetachstate</A></B>(3)).
<P>
Under the NPTL threading implementation, if the
<B>RLIMIT_STACK</B>
soft resource limit
<I>at the time the program started</I>
has any value other than &quot;unlimited&quot;,
then it determines the default stack size of new threads.
Using
<B><A HREF="/cgi-bin/man/man2html?3+pthread_attr_setstacksize">pthread_attr_setstacksize</A></B>(3),
the stack size attribute can be explicitly set in the
<I>attr</I>
argument used to create a thread,
in order to obtain a stack size other than the default.
If the
<B>RLIMIT_STACK</B>
resource limit is set to &quot;unlimited&quot;,
a per-architecture value is used for the stack size.
Here is the value for a few architectures:
<DL COMPACT><DT id="9"><DD>
<TABLE BORDER>
<TR VALIGN=top><TD><B>Architecture</B></TD><TD><B>Default stack size</B><BR></TD></TR>
<TR VALIGN=top><TD>i386</TD><TD ALIGN=right>2 MB<BR></TD></TR>
<TR VALIGN=top><TD>IA-64</TD><TD ALIGN=right>32 MB<BR></TD></TR>
<TR VALIGN=top><TD>PowerPC</TD><TD ALIGN=right>4 MB<BR></TD></TR>
<TR VALIGN=top><TD>S/390</TD><TD ALIGN=right>2 MB<BR></TD></TR>
<TR VALIGN=top><TD>Sparc-32</TD><TD ALIGN=right>2 MB<BR></TD></TR>
<TR VALIGN=top><TD>Sparc-64</TD><TD ALIGN=right>4 MB<BR></TD></TR>
<TR VALIGN=top><TD>x86_64</TD><TD ALIGN=right>2 MB<BR></TD></TR>
</TABLE>
</DL>
<A NAME="lbAK">&nbsp;</A>
<H2>BUGS</H2>
In the obsolete LinuxThreads implementation,
each of the threads in a process has a different process ID.
This is in violation of the POSIX threads specification,
and is the source of many other nonconformances to the standard; see
<B><A HREF="/cgi-bin/man/man2html?7+pthreads">pthreads</A></B>(7).
<A NAME="lbAL">&nbsp;</A>
<H2>EXAMPLE</H2>
The program below demonstrates the use of
<B>pthread_create</B>(),
as well as a number of other functions in the pthreads API.
<P>
In the following run,
on a system providing the NPTL threading implementation,
the stack size defaults to the value given by the
&quot;stack size&quot; resource limit:
<P>
$<B> ulimit -s</B>
8192 # The stack size limit is 8 MB (0x800000 bytes)
$<B> ./a.out hola salut servus</B>
Thread 1: top of stack near 0xb7dd03b8; argv_string=hola
Thread 2: top of stack near 0xb75cf3b8; argv_string=salut
Thread 3: top of stack near 0xb6dce3b8; argv_string=servus
Joined with thread 1; returned value was HOLA
Joined with thread 2; returned value was SALUT
Joined with thread 3; returned value was SERVUS
<P>
In the next run, the program explicitly sets a stack size of 1&nbsp;MB (using
<B><A HREF="/cgi-bin/man/man2html?3+pthread_attr_setstacksize">pthread_attr_setstacksize</A></B>(3))
for the created threads:
<P>
$<B> ./a.out -s 0x100000 hola salut servus</B>
Thread 1: top of stack near 0xb7d723b8; argv_string=hola
Thread 2: top of stack near 0xb7c713b8; argv_string=salut
Thread 3: top of stack near 0xb7b703b8; argv_string=servus
Joined with thread 1; returned value was HOLA
Joined with thread 2; returned value was SALUT
Joined with thread 3; returned value was SERVUS
<A NAME="lbAM">&nbsp;</A>
<H3>Program source</H3>
#include &lt;<A HREF="file:///usr/include/pthread.h">pthread.h</A>&gt;
#include &lt;<A HREF="file:///usr/include/string.h">string.h</A>&gt;
#include &lt;<A HREF="file:///usr/include/stdio.h">stdio.h</A>&gt;
#include &lt;<A HREF="file:///usr/include/stdlib.h">stdlib.h</A>&gt;
#include &lt;<A HREF="file:///usr/include/unistd.h">unistd.h</A>&gt;
#include &lt;<A HREF="file:///usr/include/errno.h">errno.h</A>&gt;
#include &lt;<A HREF="file:///usr/include/ctype.h">ctype.h</A>&gt;
<P>
#define handle_error_en(en, msg) \
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;do&nbsp;{&nbsp;errno&nbsp;=&nbsp;en;&nbsp;perror(msg);&nbsp;exit(EXIT_FAILURE);&nbsp;}&nbsp;while&nbsp;(0)
<P>
#define handle_error(msg) \
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;do&nbsp;{&nbsp;perror(msg);&nbsp;exit(EXIT_FAILURE);&nbsp;}&nbsp;while&nbsp;(0)
<P>
struct thread_info { /* Used as argument to thread_start() */
<BR>&nbsp;&nbsp;&nbsp;&nbsp;pthread_t&nbsp;thread_id;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;ID&nbsp;returned&nbsp;by&nbsp;pthread_create()&nbsp;*/
<BR>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thread_num;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Application-defined&nbsp;thread&nbsp;#&nbsp;*/
<BR>&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*argv_string;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;From&nbsp;command-line&nbsp;argument&nbsp;*/
};
<P>
/* Thread start function: display address near top of our stack,
<BR>&nbsp;&nbsp;&nbsp;and&nbsp;return&nbsp;upper-cased&nbsp;copy&nbsp;of&nbsp;argv_string&nbsp;*/
<P>
static void *
thread_start(void *arg)
{
<BR>&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;thread_info&nbsp;*tinfo&nbsp;=&nbsp;arg;
<BR>&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;*uargv,&nbsp;*p;
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;Thread&nbsp;%d:&nbsp;top&nbsp;of&nbsp;stack&nbsp;near&nbsp;%p;&nbsp;argv_string=%s\n&quot;,
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tinfo-&gt;thread_num,&nbsp;&amp;p,&nbsp;tinfo-&gt;argv_string);
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;uargv&nbsp;=&nbsp;strdup(tinfo-&gt;argv_string);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(uargv&nbsp;==&nbsp;NULL)
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handle_error(&quot;strdup&quot;);
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(p&nbsp;=&nbsp;uargv;&nbsp;*p&nbsp;!=&nbsp;'\0';&nbsp;p++)
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*p&nbsp;=&nbsp;toupper(*p);
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;uargv;
}
<P>
int
main(int argc, char *argv[])
{
<BR>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;s,&nbsp;tnum,&nbsp;opt,&nbsp;num_threads;
<BR>&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;thread_info&nbsp;*tinfo;
<BR>&nbsp;&nbsp;&nbsp;&nbsp;pthread_attr_t&nbsp;attr;
<BR>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;stack_size;
<BR>&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;*res;
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;The&nbsp;&quot;-s&quot;&nbsp;option&nbsp;specifies&nbsp;a&nbsp;stack&nbsp;size&nbsp;for&nbsp;our&nbsp;threads&nbsp;*/
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;stack_size&nbsp;=&nbsp;-1;
<BR>&nbsp;&nbsp;&nbsp;&nbsp;while&nbsp;((opt&nbsp;=&nbsp;getopt(argc,&nbsp;argv,&nbsp;&quot;s:&quot;))&nbsp;!=&nbsp;-1)&nbsp;{
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch&nbsp;(opt)&nbsp;{
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;'s':
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stack_size&nbsp;=&nbsp;strtoul(optarg,&nbsp;NULL,&nbsp;0);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default:
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr,&nbsp;&quot;Usage:&nbsp;%s&nbsp;[-s&nbsp;stack-size]&nbsp;arg...\n&quot;,
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;argv[0]);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(EXIT_FAILURE);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
<BR>&nbsp;&nbsp;&nbsp;&nbsp;}
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;num_threads&nbsp;=&nbsp;argc&nbsp;-&nbsp;optind;
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Initialize&nbsp;thread&nbsp;creation&nbsp;attributes&nbsp;*/
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;=&nbsp;pthread_attr_init(&amp;attr);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(s&nbsp;!=&nbsp;0)
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handle_error_en(s,&nbsp;&quot;pthread_attr_init&quot;);
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(stack_size&nbsp;&gt;&nbsp;0)&nbsp;{
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;=&nbsp;pthread_attr_setstacksize(&amp;attr,&nbsp;stack_size);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(s&nbsp;!=&nbsp;0)
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handle_error_en(s,&nbsp;&quot;pthread_attr_setstacksize&quot;);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;}
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Allocate&nbsp;memory&nbsp;for&nbsp;pthread_create()&nbsp;arguments&nbsp;*/
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;tinfo&nbsp;=&nbsp;calloc(num_threads,&nbsp;sizeof(struct&nbsp;thread_info));
<BR>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(tinfo&nbsp;==&nbsp;NULL)
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handle_error(&quot;calloc&quot;);
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Create&nbsp;one&nbsp;thread&nbsp;for&nbsp;each&nbsp;command-line&nbsp;argument&nbsp;*/
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(tnum&nbsp;=&nbsp;0;&nbsp;tnum&nbsp;&lt;&nbsp;num_threads;&nbsp;tnum++)&nbsp;{
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tinfo[tnum].thread_num&nbsp;=&nbsp;tnum&nbsp;+&nbsp;1;
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tinfo[tnum].argv_string&nbsp;=&nbsp;argv[optind&nbsp;+&nbsp;tnum];
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;The&nbsp;pthread_create()&nbsp;call&nbsp;stores&nbsp;the&nbsp;thread&nbsp;ID&nbsp;into
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;corresponding&nbsp;element&nbsp;of&nbsp;tinfo[]&nbsp;*/
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;=&nbsp;pthread_create(&amp;tinfo[tnum].thread_id,&nbsp;&amp;attr,
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;thread_start,&nbsp;&amp;tinfo[tnum]);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(s&nbsp;!=&nbsp;0)
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handle_error_en(s,&nbsp;&quot;pthread_create&quot;);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;}
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Destroy&nbsp;the&nbsp;thread&nbsp;attributes&nbsp;object,&nbsp;since&nbsp;it&nbsp;is&nbsp;no
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;longer&nbsp;needed&nbsp;*/
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;=&nbsp;pthread_attr_destroy(&amp;attr);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(s&nbsp;!=&nbsp;0)
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handle_error_en(s,&nbsp;&quot;pthread_attr_destroy&quot;);
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Now&nbsp;join&nbsp;with&nbsp;each&nbsp;thread,&nbsp;and&nbsp;display&nbsp;its&nbsp;returned&nbsp;value&nbsp;*/
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(tnum&nbsp;=&nbsp;0;&nbsp;tnum&nbsp;&lt;&nbsp;num_threads;&nbsp;tnum++)&nbsp;{
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;=&nbsp;pthread_join(tinfo[tnum].thread_id,&nbsp;&amp;res);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(s&nbsp;!=&nbsp;0)
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handle_error_en(s,&nbsp;&quot;pthread_join&quot;);
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;Joined&nbsp;with&nbsp;thread&nbsp;%d;&nbsp;returned&nbsp;value&nbsp;was&nbsp;%s\n&quot;,
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tinfo[tnum].thread_num,&nbsp;(char&nbsp;*)&nbsp;res);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free(res);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Free&nbsp;memory&nbsp;allocated&nbsp;by&nbsp;thread&nbsp;*/
<BR>&nbsp;&nbsp;&nbsp;&nbsp;}
<P>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;free(tinfo);
<BR>&nbsp;&nbsp;&nbsp;&nbsp;exit(EXIT_SUCCESS);
}
<A NAME="lbAN">&nbsp;</A>
<H2>SEE ALSO</H2>
<B><A HREF="/cgi-bin/man/man2html?2+getrlimit">getrlimit</A></B>(2),
<B><A HREF="/cgi-bin/man/man2html?3+pthread_attr_init">pthread_attr_init</A></B>(3),
<B><A HREF="/cgi-bin/man/man2html?3+pthread_cancel">pthread_cancel</A></B>(3),
<B><A HREF="/cgi-bin/man/man2html?3+pthread_detach">pthread_detach</A></B>(3),
<B><A HREF="/cgi-bin/man/man2html?3+pthread_equal">pthread_equal</A></B>(3),
<B><A HREF="/cgi-bin/man/man2html?3+pthread_exit">pthread_exit</A></B>(3),
<B><A HREF="/cgi-bin/man/man2html?3+pthread_getattr_np">pthread_getattr_np</A></B>(3),
<B><A HREF="/cgi-bin/man/man2html?3+pthread_join">pthread_join</A></B>(3),
<B><A HREF="/cgi-bin/man/man2html?3+pthread_self">pthread_self</A></B>(3),
<B><A HREF="/cgi-bin/man/man2html?3+pthread_setattr_default_np">pthread_setattr_default_np</A></B>(3),
<B><A HREF="/cgi-bin/man/man2html?7+pthreads">pthreads</A></B>(7)
<A NAME="lbAO">&nbsp;</A>
<H2>COLOPHON</H2>
This page is part of release 5.05 of the Linux
<I>man-pages</I>
project.
A description of the project,
information about reporting bugs,
and the latest version of this page,
can be found at
<A HREF="https://www.kernel.org/doc/man-pages/.">https://www.kernel.org/doc/man-pages/.</A>
<P>
<HR>
<A NAME="index">&nbsp;</A><H2>Index</H2>
<DL>
<DT id="10"><A HREF="#lbAB">NAME</A><DD>
<DT id="11"><A HREF="#lbAC">SYNOPSIS</A><DD>
<DT id="12"><A HREF="#lbAD">DESCRIPTION</A><DD>
<DL>
<DT id="13"><A HREF="#lbAE">Linux-specific details</A><DD>
</DL>
<DT id="14"><A HREF="#lbAF">RETURN VALUE</A><DD>
<DT id="15"><A HREF="#lbAG">ERRORS</A><DD>
<DT id="16"><A HREF="#lbAH">ATTRIBUTES</A><DD>
<DT id="17"><A HREF="#lbAI">CONFORMING TO</A><DD>
<DT id="18"><A HREF="#lbAJ">NOTES</A><DD>
<DT id="19"><A HREF="#lbAK">BUGS</A><DD>
<DT id="20"><A HREF="#lbAL">EXAMPLE</A><DD>
<DL>
<DT id="21"><A HREF="#lbAM">Program source</A><DD>
</DL>
<DT id="22"><A HREF="#lbAN">SEE ALSO</A><DD>
<DT id="23"><A HREF="#lbAO">COLOPHON</A><DD>
</DL>
<HR>
This document was created by
<A HREF="/cgi-bin/man/man2html">man2html</A>,
using the manual pages.<BR>
Time: 00:05:53 GMT, March 31, 2021
</BODY>
</HTML>