Different operating systems often have different meanings for terms such as process, thread, task, program, and so on.
In the QNX Neutrino RTOS, an application typically means a collection of processes, although sometimes—especially for UI pieces—it can mean just one process. A program is the file generated as the result of a compile and link operation; when you run a program on a QNX target, this creates a process; a process is, basically, a particular instance of a running program.
A thread is a single flow of execution or control. At the lowest level, this equates to the program counter or instruction pointer register advancing through some machine instructions. Each thread has its own current value for this register.
A process is a collection of resources shared by one or more threads. These resources include at least the following:
Along with ownership of these resources goes cleanup. When a process terminates, all process-owned resources are cleaned up, including terminating all threads, releasing all memory, closing all file descriptors, etc. This happens for both normal termination (e.g., calling exit() ) and abnormal termination (e.g., dying due to accessing invalid memory).
Threads don't share such things as stack, values for the various registers, SMP thread-affinity mask, and a few other things.
Two threads residing in two different processes don't share very much. About the only thing they do share is the CPU, and maybe not even that if they're running on a multicore processor. Threads in different processes can share memory, but this takes takes a little setup (see shm_open() in the C Library Reference for an example).
When you run a program (creating a process), you're automatically running a thread. This thread is called the main thread, since the first programmer-provided function that runs in a C program is main(). The main thread can then create additional threads if need be.
A few things are special about the main thread. One is that if it returns normally, the code it returns to calls exit(). Calling exit() terminates the process, meaning that all threads in the process are terminated. So when you return normally from the main thread, the process is terminated. When other threads in the process return normally, the code they return to calls pthread_exit(), which terminates just that thread.
Another special thing about the main thread is that if it terminates in such a manner that the process is still around (e.g., it calls pthread_exit() and there are other threads in the process), then the memory for the main thread's stack isn't freed up. This is because the command-line arguments are on that stack and other threads may need them. If any other thread terminates, then that thread's stack is freed.