1) The thread simply return from the start routine. The return value is the exit code.
2) The thread can be cancelled by another thread in the process.
3) The thread can call pthread_exit to terminate itself.
2. pthread_exit, pthread_join
Definition:
ubuntu@ip-172-31-23-227:~$ less /usr/include/pthread.h
......
/* Terminate calling thread.
The registered cleanup handlers are called via exception handling
so we cannot mark this function with __THROW.*/
extern void pthread_exit (void *__retval) __attribute__ ((__noreturn__));
/* Make calling thread wait for termination of the thread TH. The
exit status of the thread is stored in *THREAD_RETURN, if THREAD_RETURN
is not NULL.
This function is a cancellation point and therefore not marked with
__THROW. */
extern int pthread_join (pthread_t __th, void **__thread_return);
......
pthread_join will automatically put the thread into detached state, then thread's storage can be reclaimed immediately. If the thread is already in the detached state, then pthread_join normally fail, returning EINVAL.
Example:
thread.c:
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<string.h>
#include<unistd.h>
void* thr_fn1(void *arg)
{
printf("thread 1 returning \n");
return((void*)1);
}
void* thr_fn2(void *arg)
{
printf("thread 2 exiting \n");
pthread_exit((void*)2);
}
int main(int argc, char* argv[])
{
int err;
pthread_t tid1, tid2;
void *tret;
// Create the first thread, the first thread starts running
err = pthread_create(&tid1, NULL, thr_fn1, NULL);
if(err != 0) {
printf("can't create thread 1: %s\n", strerror(err));
exit(1);
}
// Create the second thread, the second thread starts running
err = pthread_create(&tid2, NULL, thr_fn2, NULL);
if(err != 0) {
printf("can't create thread 2: %s\n", strerror(err));
exit(1);
}
// Calling thread, waits for the first thread, if it exits,
// Catch the return code of it
err = pthread_join(tid1, &tret);
if(err != 0) {
printf("can't join with thread 1: %s\n", strerror(err));
exit(2);
}
printf("thread 1 return code: %ld\n", (long)tret);
sleep(2);
// Calling thread, waits for the second thread, if it exits,
// Catch the exit code of it
err = pthread_join(tid2, &tret);
if(err != 0) {
printf("can't join with thread 2: %s\n", strerror(err));
exit(2);
}
printf("thread 2 exit code: %ld\n", (long)tret);
exit(0);
}
shell:
After running the program, it outputted the first 3 lines. And then after 2 seconds, it outputted last line.
This proves that even if the newly created thread finished running, it is NOT in detached state.It is still there waiting for the pthread_join to pick up its exit code.
ubuntu@ip-172-31-23-227:~$ ./thread.out
thread 2 exiting
thread 1 returning
thread 1 return code: 1
thread 2 exit code: 2
3. thread "shared" memory overlapping
Thread can return the address of struct to return more complex information, but we need to make sure that the struct is not allocated from stack. Otherwise, after exiting from the thread, the struct's memory maybe written by sth else.
Bad Example:
thread.c:
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<unistd.h>
#include<string.h>
struct foo {
int a, b, c, d;
};
void printfoo(const char *s, const struct foo *fp)
{
printf("%s", s);
printf(" structure at 0x%lx\n", (unsigned long)fp);
printf(" foo.a = %d\n", fp->a);
printf(" foo.b = %d\n", fp->b);
printf(" foo.c = %d\n", fp->c);
printf(" foo.d = %d\n", fp->d);
}
void *thr_fn1(void *arg)
{
struct foo foo = {1, 2, 3, 4};
printfoo("thread 1:\n", &foo);
pthread_exit((void*)&foo);
}
void *thr_fn2(void *arg)
{
printf("thread 2: ID is %d\n", (int)pthread_self());
pthread_exit((void*)0);
}
int main(int argc, char* argv[])
{
int err;
pthread_t tid1, tid2;
struct foo *fp;
// Launch the first thread
err = pthread_create(&tid1, NULL, thr_fn1, NULL);
if(err != 0) {
printf("Can't create thread 1: %s\n", strerror(err));
exit(1);
}
// Wait for the first thread finish
err = pthread_join(tid1, (void*)&fp);
if(err != 0) {
printf("Can't join with thread 1: %s\n", strerror(err));
exit(2);
}
sleep(1);
// Launch the second thread
printf("Parent starting the second thread\n");
err = pthread_create(&tid2, NULL, thr_fn2, NULL);
if(err != 0) {
printf("Can't create thread 2: %s\n", strerror(err));
exit(1);
}
sleep(1);
printfoo("parent: \n", fp);
exit(0);
}
shell:
After launching the program, it started the first thread, to print out the local struct foo. And then it returned the address of local struct foo.
Next, the program launched the 2nd thread.
Finally, the program print out the struct foo based on the address returned from first thread. But the value is corrupted there(note the address remain the same), this indicate that. pthread_join make first thread's storage immediately reclaimed, and then used for sth else, which corrupted the data there.
ubuntu@ip-172-31-23-227:~$ ./thread.out
thread 1:
structure at 0x7ffc17928f00
foo.a = 1
foo.b = 2
foo.c = 3
foo.d = 4
Parent starting the second thread
thread 2: ID is 395482880
parent:
structure at 0x7ffc17928f00
foo.a = 395482880
foo.b = 32764
foo.c = 395482880
foo.d = 32764
No comments:
Post a Comment