A thread may be dynamically deleted by itself or by another one using the following service:
#include <chorus.h> int threadDelete(KnCap* actorCap, KnThreadLid thLi);
This call enables a thread to delete another one inside the same actor, when actorCap is set to K_MYACTOR, by knowing the thread identifier of the thread to be deleted. It also enables a thread to delete another one inside another actor (provided they are both running on the same machine), as long as it provides both the actor capability and the target thread identifier. The predefined thread identifier K_MYSELF enables a thread to name itself without knowing its actual thread identifier.
Example 6-2 is a slightly different version of the previous program. The subroutine childCreate() is unchanged, but now the created thread kills itself, instead of going idle forever.
This does not solve the synchronization problem occurring in the previous example: the main thread still does not know exactly when to terminate the actor.
Refer to the threadDelete(2K) man page.
(file: progov/thDelete.c) #include <stdio.h> #include <stdlib.h> #include <chorus.h> #define USER_STACK_SIZE (1024 * sizeof(long)) int childCreate(KnPc entry) { KnActorPrivilege actorP; KnDefaultStartInfo_f startInfo; char* userStack; int childLid = -1; int res; startInfo.dsType = K_DEFAULT_START_INFO; startInfo.dsSystemStackSize = K_DEFAULT_STACK_SIZE; res = actorPrivilege(K_MYACTOR, &actorP, NULL); if (res != K_OK) { printf("Cannot get the privilege of the actor, error %d\n", res); exit(1); } if (actorP == K_SUPACTOR) { startInfo.dsPrivilege = K_SUPTHREAD; } else { startInfo.dsPrivilege = K_USERTHREAD; } if (actorP != K_SUPACTOR) { userStack = malloc(USER_STACK_SIZE); if (userStack == NULL) { printf("Cannot allocate user stack\n"); exit(1); } startInfo.dsUserStackPointer = userStack + USER_STACK_SIZE; } startInfo.dsEntry = entry; res = threadCreate(K_MYACTOR, &childLid, K_ACTIVE, 0, &startInfo); if (res != K_OK) { printf("Cannot create the thread, error %d\n", res); exit(1); } return childLid; } void sampleThread() { int myThreadLi; myThreadLi = threadSelf(); printf("I am the new thread. My thread identifier is: %d\n", myThreadLi); /* Suicide */ threadDelete(K_MYACTOR, K_MYSELF); /* Should never reach this point! */ } int main(int argc, char** argv, char**envp) { int myThreadLi; int newThreadLi; int res; KnTimeVal wait; newThreadLi = childCreate((KnPc)sampleThread); myThreadLi = threadSelf(); /* Initialize KnTimeVal structure */ K_MILLI_TO_TIMEVAL(&wait, 10); /* * Suspend myself for 10 milliseconds to give the newly * created thread the opportunity to run before * the actor terminates. */ res = threadDelay(&wait); printf("Parent thread identifier = %d, Child thread identifier = %d\n", myThreadLi, newThreadLi); return 0; }
The exit() function is used instead of the threadDelete() function in the main thread. Using threadDelete() would leave the actor in a passive situation, with no thread running within it. This implies that resources used by an actor are not freed when the last thread is deleted.
In the case of a user thread, deleting a thread does not imply that the stack of the thread will be freed. If the user stack was allocated through a call to malloc(), it must be freed through a call to free(). This cannot be done by the thread itself, it must be done by another thread. In the above example, the actor is going to terminate, so there is no real need to do this because all resources used by the actor will be returned to the system. In the case of a supervisor thread, the ChorusOS operating system frees the system stack it had allocated at threadCreate() time.