Starting and Ending Threads


Threads, as you recall, differ from child tasks in that they are more tightly bound to their parent task. They share the parent task's memory and can't transfer their ownership. However, they still need to be started and ended just as tasks do. This section describes the calls used to start and end threads.

Creating a Thread

The CreateThread() function creates a thread:

Item CreateThread ( cconst char *name, uint8 pri, void (*code) (), int32 stacksize )
The first argument, name, is the name of the thread to create. The second argument, pri, is the priority that the thread will have. The third argument, code, is a pointer to the code that the thread will execute. The last argument, stacksize, specifies the size in bytes of the thread's stack. If successful, the call returns the item number of the thread. If unsuccessful, it returns an error code.

Before calling CreateThread(), you must determine what stack size to use for the thread. There is no default size for the stacksize argument; however, it's important to make the size large enough so that stack overflow errors do not occur. Stack overflow errors are characterized by random crashes that defy logical analysis, so it's a good approach to start with a large stack size and reduce it until a crash occurs, then double the stack size. In the sample code later in this chapter, the stack size is set to 10000. A good size to start with is 2048.

Example 1 shows the process of creating a thread:

Example 1: Starting a task.

#define STACKSIZE (10000)
...
int main(int argc, char *argv[])
{
uint8  Priority;
Item  T1;
...
Priority = CURRENTTASK->t.n_Priority;
T1 = CreateThread("Thread1", Priority, Thread1Proc, STACKSIZE);
...
}
int Thread1Proc()
{
/* This is the code for Thread1Proc */
}

Communication

Because threads share memory with the parent task, global variables can pass information among threads and tasks. In the sample code later in this chapter a number of global variables are declared at the start of the program, prior to the code for the threads and the parent task code. As global variables, they are accessible to the main routine and to the threads-an example of threads sharing the same memory as the parent task.

The code example given at the end of this chapter is a good illustration of using CreateThread() to start two threads. It shows the use of global variables that are shared by all threads, which signal among threads and the parent task. Signals for both threads are first allocated with AllocSignal(). The parent task then uses WaitSignal() to wait for an event from either of the threads.

Opening Folios

Whenever you make folio calls from a thread, be sure to open the appropriate folios first. It's tempting to think that because a folio has been opened by the parent task, the thread can make calls from the same folio without opening it. Not true-and potentially fatal to the thread. Each thread must open all folios it intends to use.

Ending a Thread

Use DeleteThread() to end a thread when a parent task finishes with it:

Err DeleteThread( Item thread )
This function takes the item number of the thread to delete as its only argument, and returns a negative error code if an error occurs. Although all threads terminate automatically when the parent task ceases, it's good programming practice to kill a thread as soon as the parent task finishes using it. Note that when you terminate a thread, the thread's memory (which is shared with the parent task) is not freed, and remains the property of the parent task. A thread can also terminate itself by calling exit() or just returning.

Advanced Thread Usage

The CreateThread() and DeleteThread() functions are convenience routines, which make it easy to create and delete threads for the most common uses. It is sometimes necessary to have better control over thread creation. This requires allocating resources yourself and creating the thread item using CreateItem() or CreateItemVA().

Creating a thread involves allocating memory for the stack that the thread will use, and constructing a tag argument list that describes how the thread should be created. The tags you supply are: