A thread can terminate its execution in the following ways:
By returning from its first (outermost) procedure, the threads start routine; see pthread_create(3T)
By termination with POSIX cancel functions; see pthread_cancel()
The default behavior of a thread is to linger until some other thread has acknowledged its demise by "joining" with it. This is the same as the default pthread_create() attribute being non-detached; see pthread_detach(3T). The result of the join is that the joining thread picks up the exit status of the dying thread and the dying thread vanishes.
An important special case arises when the initial thread -- the one calling main(),-- returns from calling main() or calls exit(3C). This action causes the entire process to be terminated, along with all its threads. So take care to ensure that the initial thread does not return from main() prematurely.
Note that when the main thread merely calls pthread_exit(3T), it terminates only itself--the other threads in the process, as well as the process, continue to exist. (The process terminates when all threads terminate.)