📄 kernel-thread-create.html
字号:
<!-- Copyright (C) 2003 Red Hat, Inc. --><!-- This material may be distributed only subject to the terms --><!-- and conditions set forth in the Open Publication License, v1.0 --><!-- or later (the latest version is presently available at --><!-- http://www.opencontent.org/openpub/). --><!-- Distribution of the work or derivative of the work in any --><!-- standard (paper) book form is prohibited unless prior --><!-- permission is obtained from the copyright holder. --><HTML><HEAD><TITLE>Thread creation</TITLE><meta name="MSSmartTagsPreventParsing" content="TRUE"><METANAME="GENERATOR"CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+"><LINKREL="HOME"TITLE="eCos Reference Manual"HREF="ecos-ref.html"><LINKREL="UP"TITLE="The eCos Kernel"HREF="kernel.html"><LINKREL="PREVIOUS"TITLE="SMP Support"HREF="kernel-smp.html"><LINKREL="NEXT"TITLE="Thread information"HREF="kernel-thread-info.html"></HEAD><BODYCLASS="REFENTRY"BGCOLOR="#FFFFFF"TEXT="#000000"LINK="#0000FF"VLINK="#840084"ALINK="#0000FF"><DIVCLASS="NAVHEADER"><TABLESUMMARY="Header navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><THCOLSPAN="3"ALIGN="center">eCos Reference Manual</TH></TR><TR><TDWIDTH="10%"ALIGN="left"VALIGN="bottom"><AHREF="kernel-smp.html"ACCESSKEY="P">Prev</A></TD><TDWIDTH="80%"ALIGN="center"VALIGN="bottom"></TD><TDWIDTH="10%"ALIGN="right"VALIGN="bottom"><AHREF="kernel-thread-info.html"ACCESSKEY="N">Next</A></TD></TR></TABLE><HRALIGN="LEFT"WIDTH="100%"></DIV><H1><ANAME="KERNEL-THREAD-CREATE">Thread creation</H1><DIVCLASS="REFNAMEDIV"><ANAME="AEN256"></A><H2>Name</H2>cyg_thread_create -- Create a new thread</DIV><DIVCLASS="REFSYNOPSISDIV"><ANAME="AEN259"><H2>Synopsis</H2><DIVCLASS="FUNCSYNOPSIS"><ANAME="AEN260"><P></P><TABLEBORDER="5"BGCOLOR="#E0E0F0"WIDTH="70%"><TR><TD><PRECLASS="FUNCSYNOPSISINFO">#include <cyg/kernel/kapi.h> </PRE></TD></TR></TABLE><P><CODE><CODECLASS="FUNCDEF">void cyg_thread_create</CODE>(cyg_addrword_t sched_info, cyg_thread_entry_t* entry, cyg_addrword_t entry_data, char* name, void* stack_base, cyg_ucount32 stack_size, cyg_handle_t* handle, cyg_thread* thread);</CODE></P><P></P></DIV></DIV><DIVCLASS="REFSECT1"><ANAME="KERNEL-THREAD-CREATE-DESCRIPTION"></A><H2>Description</H2><P>The <TTCLASS="FUNCTION">cyg_thread_create</TT> function allows applicationcode and eCos packages to create new threads. In many applicationsthis only happens during system initialization and all required datais allocated statically. However additional threads can be created atany time, if necessary. A newly created thread is always in suspendedstate and will not start running until it has been resumed via a callto <TTCLASS="FUNCTION">cyg_thread_resume</TT>. Also, if threads arecreated during system initialization then they will not start runninguntil the eCos scheduler has been started. </P><P>The <TTCLASS="PARAMETER"><I>name</I></TT> argument is usedprimarily for debugging purposes, making it easier to keep track ofwhich <SPANCLASS="STRUCTNAME">cyg_thread</SPAN> structure is associated withwhich application-level thread. The kernel configuration option<TTCLASS="VARNAME">CYGVAR_KERNEL_THREADS_NAME</TT> controls whether or notthis name is actually used. </P><P>On creation each thread is assigned a unique handle, and this will bestored in the location pointed at by the <TTCLASS="PARAMETER"><I>handle</I></TT> argument. Subsequent operations onthis thread including the required<TTCLASS="FUNCTION">cyg_thread_resume</TT> should use this handle toidentify the thread. </P><P>The kernel requires a small amount of space for each thread, in theform of a <SPANCLASS="STRUCTNAME">cyg_thread</SPAN> data structure, to holdinformation such as the current state of that thread. To avoid anyneed for dynamic memory allocation within the kernel this space has tobe provided by higher-level code, typically in the form of a staticvariable. The <TTCLASS="PARAMETER"><I>thread</I></TT> argumentprovides this space. </P></DIV><DIVCLASS="REFSECT1"><ANAME="KERNEL-THREAD-CREATE-ENTRY"></A><H2>Thread Entry Point</H2><P>The entry point for a thread takes the form: </P><TABLEBORDER="5"BGCOLOR="#E0E0F0"WIDTH="70%"><TR><TD><PRECLASS="PROGRAMLISTING">voidthread_entry_function(cyg_addrword_t data){ …} </PRE></TD></TR></TABLE><P>The second argument to <TTCLASS="FUNCTION">cyg_thread_create</TT> is apointer to such a function. The third argument <TTCLASS="PARAMETER"><I>entry_data</I></TT> is used to pass additionaldata to the function. Typically this takes the form of a pointer tosome static data, or a small integer, or <TTCLASS="LITERAL">0</TT> if thethread does not require any additional data. </P><P>If the thread entry function ever returns then this is equivalent tothe thread calling <TTCLASS="FUNCTION">cyg_thread_exit</TT>. Even thoughthe thread will no longer run again, it remains registered with thescheduler. If the application needs to re-use the<SPANCLASS="STRUCTNAME">cyg_thread</SPAN> data structure then a call to<TTCLASS="FUNCTION">cyg_thread_delete</TT> is required first. </P></DIV><DIVCLASS="REFSECT1"><ANAME="KERNEL-THREAD-CREATE-PRIORITIES"></A><H2>Thread Priorities</H2><P>The <TTCLASS="PARAMETER"><I>sched_info</I></TT> argumentprovides additional information to the scheduler. The exact detailsdepend on the scheduler being used. For the bitmap and mlqueueschedulers it is a small integer, typically in the range 0 to 31, with0 being the highest priority. The lowest priority is normally usedonly by the system's idle thread. The exact number of priorities iscontrolled by the kernel configuration option<TTCLASS="VARNAME">CYGNUM_KERNEL_SCHED_PRIORITIES</TT>. </P><P>It is the responsibility of the application developer to be aware ofthe various threads in the system, including those created by eCospackages, and to ensure that all threads run at suitable priorities.For threads created by other packages the documentation provided bythose packages should indicate any requirements. </P><P>The functions <TTCLASS="FUNCTION">cyg_thread_set_priority</TT>,<TTCLASS="FUNCTION">cyg_thread_get_priority</TT>, and<TTCLASS="FUNCTION">cyg_thread_get_current_priority</TT> can be used tomanipulate a thread's priority. </P></DIV><DIVCLASS="REFSECT1"><ANAME="KERNEL-THREAD-CREATE-STACK"></A><H2>Stacks and Stack Sizes</H2><P>Each thread needs its own stack for local variables and to keep trackof function calls and returns. Again it is expected that this stack isprovided by the calling code, usually in the form of static data, sothat the kernel does not need any dynamic memory allocationfacilities. <TTCLASS="FUNCTION">cyg_thread_create</TT> takes two argumentsrelated to the stack, a pointer to the base of the stack and the totalsize of this stack. On many processors stacks actually descend from thetop down, so the kernel will add the stack size to the base address todetermine the starting location. </P><P>The exact stack size requirements for any given thread depend on anumber of factors. The most important is of course the code that willbe executed in the context of this code: if this involves significantnesting of function calls, recursion, or large local arrays, then thestack size needs to be set to a suitably high value. There are somearchitectural issues, for example the number of cpu registers and thecalling conventions will have some effect on stack usage. Also,depending on the configuration, it is possible that some other codesuch as interrupt handlers will occasionally run on the currentthread's stack. This depends in part on configuration options such as<TTCLASS="VARNAME">CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK</TT>and <TTCLASS="VARNAME">CYGSEM_HAL_COMMON_INTERRUPTS_ALLOW_NESTING</TT>. </P><P>Determining an application's actual stack size requirements is theresponsibility of the application developer, since the kernel cannotknow in advance what code a given thread will run. However, the systemdoes provide some hints about reasonable stack sizes in the form oftwo constants: <TTCLASS="VARNAME">CYGNUM_HAL_STACK_SIZE_MINIMUM</TT> and<TTCLASS="VARNAME">CYGNUM_HAL_STACK_SIZE_TYPICAL</TT>. These are defined bythe appropriate HAL package. The <TTCLASS="VARNAME">MINIMUM</TT> value isappropriate for a thread that just runs a single function and makesvery simple system calls. Trying to create a thread with a smallerstack than this is illegal. The <TTCLASS="VARNAME">TYPICAL</TT> value isappropriate for applications where application calls are nested nomore than half a dozen or so levels, and there are no large arrays onthe stack. </P><P>If the stack sizes are not estimated correctly and a stack overflowoccurs, the probably result is some form of memory corruption. Thiscan be very hard to track down. The kernel does contain some code tohelp detect stack overflows, controlled by the configuration option<TTCLASS="VARNAME">CYGFUN_KERNEL_THREADS_STACK_CHECKING</TT>: a smallamount of space is reserved at the stack limit and filled with aspecial signature: every time a thread context switch occurs thissignature is checked, and if invalid that is a good indication (butnot absolute proof) that a stack overflow has occurred. This form ofstack checking is enabled by default when the system is built withdebugging enabled. A related configuration option is<TTCLASS="VARNAME">CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT</TT>: enablingthis option means that a thread can call the function<TTCLASS="FUNCTION">cyg_thread_measure_stack_usage</TT> to find out themaximum stack usage to date. Note that this is not necessarily thetrue maximum because, for example, it is possible that in the currentrun no interrupt occurred at the worst possible moment. </P></DIV><DIVCLASS="REFSECT1"><ANAME="KERNEL-THREAD-CREATE-CONTEXT"></A><H2>Valid contexts</H2><P><TTCLASS="FUNCTION">cyg_thread_create</TT> may be called duringinitialization and from within thread context. It may not be calledfrom inside a DSR. </P></DIV><DIVCLASS="REFSECT1"><ANAME="KERNEL-THREAD-CREATE-EXAMPLE"></A><H2>Example</H2><P>A simple example of thread creation is shown below. This involvescreating five threads, one producer and four consumers or workers. Thethreads are created in the system's<TTCLASS="FUNCTION">cyg_user_start</TT>: depending on the configuration itmight be more appropriate to do this elsewhere, for example inside<TTCLASS="FUNCTION">main</TT>. </P><TABLEBORDER="5"BGCOLOR="#E0E0F0"WIDTH="70%"><TR><TD><PRECLASS="PROGRAMLISTING">#include <cyg/hal/hal_arch.h>#include <cyg/kernel/kapi.h>// These numbers depend entirely on your application#define NUMBER_OF_WORKERS 4#define PRODUCER_PRIORITY 10#define WORKER_PRIORITY 11#define PRODUCER_STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL#define WORKER_STACKSIZE (CYGNUM_HAL_STACK_SIZE_MINIMUM + 1024)static unsigned char producer_stack[PRODUCER_STACKSIZE];static unsigned char worker_stacks[NUMBER_OF_WORKERS][WORKER_STACKSIZE];static cyg_handle_t producer_handle, worker_handles[NUMBER_OF_WORKERS];static cyg_thread_t producer_thread, worker_threads[NUMBER_OF_WORKERS];static voidproducer(cyg_addrword_t data){ …}static voidworker(cyg_addrword_t data){ …}voidcyg_user_start(void){ int i; cyg_thread_create(PRODUCER_PRIORITY, &producer, 0, "producer", producer_stack, PRODUCER_STACKSIZE, &producer_handle, &producer_thread); cyg_thread_resume(producer_handle); for (i = 0; i < NUMBER_OF_WORKERS; i++) { cyg_thread_create(WORKER_PRIORITY, &worker, i, "worker", worker_stacks[i], WORKER_STACKSIZE, &(worker_handles[i]), &(worker_threads[i])); cyg_thread_resume(worker_handles[i]); }} </PRE></TD></TR></TABLE></DIV><DIVCLASS="REFSECT1"><ANAME="KERNEL-THREAD-CREATE-CXX"></A><H2>Thread Entry Points and C++</H2><P>For code written in C++ the thread entry function must be either astatic member function of a class or an ordinary function outside anyclass. It cannot be a normal member function of a class because suchmember functions take an implicit additional argument<TTCLASS="VARNAME">this</TT>, and the kernel has no way of knowing whatvalue to use for this argument. One way around this problem is to makeuse of a special static member function, for example: </P><TABLEBORDER="5"BGCOLOR="#E0E0F0"WIDTH="70%"><TR><TD><PRECLASS="PROGRAMLISTING">class fred { public: void thread_function(); static void static_thread_aux(cyg_addrword_t);};voidfred::static_thread_aux(cyg_addrword_t objptr){ fred* object = static_cast<fred*>(objptr); object->thread_function();}static fred instance;extern "C" voidcyg_start( void ){ … cyg_thread_create( …, &fred::static_thread_aux, static_cast<cyg_addrword_t>(&instance), …); …} </PRE></TD></TR></TABLE><P>Effectively this uses the <TTCLASS="PARAMETER"><I>entry_data</I></TT> argument to<TTCLASS="FUNCTION">cyg_thread_create</TT> to hold the<TTCLASS="VARNAME">this</TT> pointer. Unfortunately this approach doesrequire the use of some C++ casts, so some of the type safety that canbe achieved when programming in C++ is lost. </P></DIV><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLESUMMARY="Footer navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="kernel-smp.html"ACCESSKEY="P">Prev</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="ecos-ref.html"ACCESSKEY="H">Home</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="kernel-thread-info.html"ACCESSKEY="N">Next</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">SMP Support</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="kernel.html"ACCESSKEY="U">Up</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">Thread information</TD></TR></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -