4.6. Understanding ProcessesProcesses are the fundamental units of computation in an Impulse C application. Once they have been created, assigned, and started, the processes in an application execute as independently synchronized units of code on the target platform. Programming with Impulse C processes is conceptually similar to programming with threads. As with thread programming, each Impulse C process has its own control flow, is independently synchronized, and has access to its own local memory resources (which will vary depending on the target platform). For this reason it is relatively easy to convert applications written in threaded C (for example, using the Posix thread library) to Impulse C. There are some key differences, however:
The Impulse C desktop simulation library is based on a threading model, so global variables and heap memory are shared. Also, during simulation all Impulse C processes are executed on one processing element (your desktop computer), although this may not be the case on the target platform. It is your responsibility as the programmer to avoid using global variables and heap memory allocated outside of the Impulse C library. Note In desktop simulation, when all processes are translated to software running on a single processor, the scheduling of instructions being executed within each process is predictable, but the scheduling of instructions across processes depends on the threading model used in the host compiler and/or the host operating system. This can result in behavioral differences between software and hardware implementations of an application. In particular, your application must not assume that one process will start and execute before another process starts and executes. If such process synchronization is required, you should use signals, which are described later in this chapter, or rethink your application's use of streams.
Creating ProcessesProcesses are created and named in the configuration function of your application. In the following example, the my_app_configuration function declares three processes (procHost1, procPe1, and procPe2) and associates these processes with three corresponding process run functions named Host1, Pe1, and Pe2: #define BUFSIZE 4 void my_app_configuration() { co_process procHost1, procPe1, procPe2; co_stream s1, s2; s1 = co_stream_create("s1", INT_TYPE(16), BUFSIZE); s2 = co_stream_create("s2", INT_TYPE(16), BUFSIZE); procHost1 = co_process_create("Host1", (co_function)Host1, 1, s1); procPe1 = co_process_create("Pe1", (co_function)Pe1, 2, s1, s2); procPe2 = co_process_create("Pe2", (co_function)Pe2, 1, s2); } The co_process_create function is used to define both hardware and software processes. Unless otherwise assigned, all processes created using the co_create_process function are assumed to be software processes. The function accepts three or more arguments. The first argument must be a pointer to a character string (NULL terminated) containing a process name. This name does not have to match the variable name used within the process itself; it is only used as a label when monitoring the process externallyfor example, using the application monitor. The second argument to co_process_create is a function pointer of type co_function. This function pointer identifies the specific run function that is to be associated with (or instantiated from) the call to co_process_create. The third argument to co_process_create indicates the number of ports (inputs and outputs) that are defined by the process. This number must match the number of actual port arguments that follow and must also match the parameters of the specified run function. For example, if the number of ports is two, there must be two ports declared as arguments four and five. Tip Specifying the wrong number or wrong order of ports in the co_process_create function is a common mistake and can be difficult to debug. This is particularly true when connecting streams, which may appear to compile properly, yet exhibit incorrect behavior during simulation. Check these connections carefully. Port arguments specified for an Impulse C run process may be one of five distinct types:
Variables of these types must be declared in the configuration function and (in the case of co_stream, co_signal, co_register, and co_memory) the appropriate co_xxxxx_create function must be used to create an instance of the desired communication channel. When your application creates a process using the co_process_create function, the process is configured to run, and it begins execution, when the co_execute function is called at the start of the program's execution. This is a fundamental difference between thread programming and programming in Impulse C: in Impulse C, the entire application and all its parallel processing components are set up in advance to minimize runtime overhead. |