⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 programming.sgml

📁 开放源码实时操作系统源码.
💻 SGML
📖 第 1 页 / 共 4 页
字号:
<PROGRAMLISTING>
#include &lt;cyg/kernel/kapi.h&#62;
#include &lt;stdio.h&#62;
#include &lt;math.h&#62;
#include &lt;stdlib.h&#62;

/* now declare (and allocate space for) some kernel objects,
  like the two threads we will use */
cyg_thread thread_s[2];	/* space for two thread objects */

char stack[2][4096];	/* space for two 4K stacks */

/* now the handles for the threads */
cyg_handle_t simple_threadA, simple_threadB;

/* and now variables for the procedure which is the thread */
cyg_thread_entry_t simple_program;

/* and now a mutex to protect calls to the C library */
cyg_mutex_t cliblock;

/* we install our own startup routine which sets up threads */
void cyg_user_start(void)
{
 printf("Entering twothreads' cyg_user_start() function\n");

 cyg_mutex_init(&amp;cliblock);

 cyg_thread_create(4, simple_program, (cyg_addrword_t) 0,
	"Thread A", (void *) stack[0], 4096,
	&amp;simple_threadA, &amp;thread_s[0]);
 cyg_thread_create(4, simple_program, (cyg_addrword_t) 1,
	"Thread B", (void *) stack[1], 4096,
	&amp;simple_threadB, &amp;thread_s[1]);

 cyg_thread_resume(simple_threadA);
 cyg_thread_resume(simple_threadB);
}

/* this is a simple program which runs in a thread */
void simple_program(cyg_addrword_t data)
{
 int message = (int) data;
 int delay;

 printf("Beginning execution; thread data is %d\n", message);

 cyg_thread_delay(200);

 for (;;) {
 delay = 200 + (rand() % 50);

 /* note: printf() must be protected by a
 call to cyg_mutex_lock() */
 cyg_mutex_lock(&amp;cliblock); {
 printf("Thread %d: and now a delay of %d clock ticks\n",
	message, delay);
 }
 cyg_mutex_unlock(&amp;cliblock);
 cyg_thread_delay(delay);
 }
}
</PROGRAMLISTING>

<PARA>
When you run the program (by typing <command>continue</command> at
the (<EMPHASIS>gdb</EMPHASIS>) prompt) the output should look like
this:</PARA>

<PROGRAMLISTING>
Starting program: <replaceable>BASE_DIR</replaceable>/examples/twothreads.exe
Entering twothreads' cyg_user_start()
function
Beginning execution; thread data is 0
Beginning execution; thread data is 1
Thread 0: and now a delay of 240 clock ticks
Thread 1: and now a delay of 225 clock ticks
Thread 1: and now a delay of 234 clock ticks
Thread 0: and now a delay of 231 clock ticks
Thread 1: and now a delay of 224 clock ticks
Thread 0: and now a delay of 249 clock ticks
Thread 1: and now a delay of 202 clock ticks
Thread 0: and now a delay of 235 clock ticks
</PROGRAMLISTING>

<NOTE>
<PARA>When running in a simulator the <!-- <index></index> -->
delays might be quite long. On a hardware board (where the clock
speed is 100 ticks/second) the delays should average to
about 2.25 seconds. In simulation, the delay will depend on the
speed of the host processor and will almost always be much slower than
the actual board. You might want to reduce the delay parameter when running
in simulation.
</PARA>
</NOTE>

<PARA>
<XREF LINKEND="FIGURE-TWOTHREADS-WITH-SIMPLE-PRINTS"> shows how this
multitasking program executes.  Note that apart from the thread
creation system calls, this program also creates and uses a
<EMPHASIS><!-- <index></index> -->mutex</EMPHASIS> for synchronization
between the <function>printf()</function> calls in the two
threads. This is because the C library standard I/O (by default) is
configured not to be thread-safe, which means that if more than one
thread is using standard I/O they might corrupt each other. This is
fixed by a mutual exclusion (or <EMPHASIS>mutex</EMPHASIS>) lockout
mechanism: the threads do not call <function>printf()</function> until
<function>cyg_mutex_lock()</function> has returned, which only happens
when the other thread calls
<function>cyg_mutex_unlock()</function>.</PARA>

<PARA>You could avoid using the mutex by configuring the C library to
be thread-safe (by selecting the component
<LITERAL>CYGSEM_LIBC_STDIO_THREAD_SAFE_STREAMS</LITERAL>).</PARA>

<FIGURE
ID="FIGURE-TWOTHREADS-WITH-SIMPLE-PRINTS"><!-- <xref> --> <TITLE>Two
threads with simple print statements after random delays</TITLE>
<GRAPHIC ENTITYREF="programming-graphic9"></GRAPHIC>
</FIGURE>

</SECT2>

</SECT1>

</CHAPTER>

<!-- ==================================================== -->

<CHAPTER ID="CLOCKS-AND-ALARM-HANDLERS">
<TITLE>More Features &mdash; <!-- <index></index> -->Clocks and Alarm
Handlers</TITLE>

<PARA>If a program wanted to execute a task at a given time, or
periodically, it could do it in an inefficient way by sitting in a
loop and checking the real-time clock to see if the proper amount of
time has elapsed. But operating systems usually provide system calls
which allow the program to be informed at the desired time.</PARA>

<PARA><productname>eCos</productname> provides a rich timekeeping formalism, involving
<EMPHASIS>counters</EMPHASIS>, <EMPHASIS>clocks</EMPHASIS>,
<EMPHASIS>alarms</EMPHASIS>, and <EMPHASIS>timers</EMPHASIS>.  The
precise definition, relationship, and motivation of these features is
beyond the scope of this tutorial, but these examples illustrate how
to set up basic periodic tasks.</PARA>

<PARA><!-- <index></index> -->Alarms are events that happen at
a given time, either once or periodically. A thread associates an
alarm handling function with the alarm, so that the function will
be invoked every time the alarm &ldquo;goes off&rdquo;.</PARA>

<!-- ==================================================== -->

<SECT1 id="sample-alarms">
<TITLE>A Sample Program with Alarms</TITLE>

<PARA><!-- <index></index> --><FILENAME>simple-alarm.c</FILENAME> (in
the examples directory) is a short program that creates a thread that
creates an alarm. The alarm is handled by the function
<FUNCTION>test_alarm_func()</FUNCTION>, which sets a global
variable. When the main thread of execution sees that the variable has
changed, it prints a message.</PARA>

<EXAMPLE>
<TITLE>A sample <!-- <index></index> -->program that creates an alarm</TITLE>

<PROGRAMLISTING>
/* this is a very simple program meant to demonstrate
 a basic use of time, alarms and alarm-handling functions  in eCos */

#include &lt;cyg/kernel/kapi.h&#62;

#include &lt;stdio.h&#62;

#define NTHREADS 1
#define STACKSIZE 4096

static cyg_handle_t thread[NTHREADS];

static cyg_thread thread_obj[NTHREADS];
static char stack[NTHREADS][STACKSIZE];

static void alarm_prog( cyg_addrword_t data );

/* we install our own startup routine which sets up
  threads and starts the scheduler */
void cyg_user_start(void)
{
 cyg_thread_create(4, alarm_prog, (cyg_addrword_t) 0,
	"alarm_thread", (void *) stack[0],
	STACKSIZE, &amp;thread[0], &amp;thread_obj[0]);
 cyg_thread_resume(thread[0]);
}

/* we need to declare the alarm handling function (which is
 defined below), so that we can pass it to  cyg_alarm_initialize() */
cyg_alarm_t test_alarm_func;

/* alarm_prog() is a thread which sets up an alarm which is then
 handled by test_alarm_func() */
static void alarm_prog(cyg_addrword_t data)
{
 cyg_handle_t test_counterH, system_clockH, test_alarmH;
 cyg_tick_count_t ticks;
 cyg_alarm test_alarm;
 unsigned how_many_alarms = 0, prev_alarms = 0, tmp_how_many;

 system_clockH = cyg_real_time_clock();
 cyg_clock_to_counter(system_clockH, &amp;test_counterH);
 cyg_alarm_create(test_counterH, test_alarm_func,
	(cyg_addrword_t) &amp;how_many_alarms,
	&amp;test_alarmH, &amp;test_alarm);
 cyg_alarm_initialize(test_alarmH, cyg_current_time()+200, 200);

 /* get in a loop in which we read the current time and
    print it out, just to have something scrolling by */
 for (;;) {
   ticks = cyg_current_time();
   printf("Time is %llu\n", ticks);
   /* note that we must lock access to how_many_alarms, since the
   alarm handler might change it. this involves using the
   annoying temporary variable tmp_how_many so that I can keep the
   critical region short */
   cyg_scheduler_lock();
   tmp_how_many = how_many_alarms;
   cyg_scheduler_unlock();
   if (prev_alarms != tmp_how_many) {
     printf(" --- alarm calls so far: %u\n", tmp_how_many);
     prev_alarms = tmp_how_many;
   }
   cyg_thread_delay(30);
 }
}

/* test_alarm_func() is invoked as an alarm handler, so
   it should be quick and simple. in this case it increments
   the data that is passed to it. */
void test_alarm_func(cyg_handle_t alarmH, cyg_addrword_t data)
{
 ++*((unsigned *) data);
}
</PROGRAMLISTING>
</EXAMPLE>

<PARA>When you run this program (by typing <COMMAND>continue</COMMAND> at
the (<EMPHASIS>gdb</EMPHASIS>) prompt) the output should look like
this:</PARA>
<SCREEN>
Starting program: <replaceable>BASE_DIR</replaceable>/examples/simple-alarm.exe
Time is 0
Time is 30
Time is 60
Time is 90
Time is 120
Time is 150
Time is 180
Time is 210
  --- alarm calls so far: 1
Time is 240
Time is 270
Time is 300
Time is 330
Time is 360
Time is 390
Time is 420
  --- alarm calls so far: 2
Time is 450
Time is 480
</SCREEN>

<NOTE>
<PARA>When running in a simulator the <!-- <index></index> --> delays
might be quite long. On a hardware board (where the clock speed is 100
ticks/second) the delays should average to about 0.3 seconds (and 2
seconds between alarms). In simulation, the delay will depend on the
speed of the host processor and will almost always be much slower than
the actual board. You might want to reduce the delay parameter when
running in simulation.</PARA>
</NOTE>

<PARA>Here are a few things you might notice about this program:</PARA>

<ITEMIZEDLIST>
<LISTITEM>
<PARA>It used the <function>cyg_real_time_clock()</function> function;
this always returns a handle to the default system real-time <!--
<index></index> --> clock. </PARA>
</LISTITEM>

<LISTITEM>
<PARA><!-- <index></index> -->Clocks are based on <!-- <index></index>
--> counters, so the function <function>cyg_alarm_create()</function>
uses a counter handle. The program used the function
<function>cyg_clock_to_counter()</function> to strip the clock handle
to the underlying counter handle. </PARA>
</LISTITEM>

<LISTITEM>
<PARA>Once the alarm is created it is <!-- <index></index> -->
initialized with <function>cyg_alarm_initialize()</function>, which
sets the time at which the alarm should go off, as well as the period
for repeating alarms. It is set to go off at the current time and
then to repeat every 200 ticks. </PARA>
</LISTITEM>

<LISTITEM>
<PARA>The alarm handler function
<function>test_alarm_func()</function> conforms to the guidelines for
writing alarm handlers and other <!-- <index></index> --><!--
<index></index> --> delayed service routines: it does not invoke any
functions which might lock the scheduler.  This is discussed in detail
in the <CITETITLE><productname>eCos</productname> Reference Manual</CITETITLE>, in the chapter
<citetitle>The <productname>eCos</productname> Kernel</citetitle>.</PARA>
</LISTITEM>

<LISTITEM>
<PARA>There is a <EMPHASIS>critical region</EMPHASIS> in this program:
the variable <LITERAL>how_many_alarms</LITERAL> is accessed in the
main thread of control and is also modified in the alarm handler. To
prevent a possible (though unlikely) race condition on this variable,
access to <LITERAL>how_many_alarms</LITERAL> in the principal thread
is protected by calls to <FUNCTION>cyg_scheduler_lock()</FUNCTION> and
<FUNCTION>cyg_scheduler_unlock()</FUNCTION>. When the scheduler is
locked, the alarm handler will not be invoked, so the problem is
averted. </PARA>
</LISTITEM>
</ITEMIZEDLIST>
</SECT1>
</CHAPTER>

</part>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -