几回魂梦与君同——线程相关函数

2019-07-14 11:46发布

创建线程后进程的地址空间没有变化,该进程退化为主线程。 创建出的子线程和主线程共用一块地址空间,但他们有各自独立的PCB,而子线程的PCB是从主线程拷贝来的。 子线程在不设置分离属性的前提下,必须由主线程来释放其PCB。 主线程程和子线程除了不共享用户空间的,其他的都共享。例如,假如有五个线程,则用户空间的栈被平均分成五份,各自使用。所以,我们也可以通过全局变量或者堆上的数据进行线程间的通信。

创建线程

          #include           int pthread_create(pthread_t thread, const pthread_attr_t* attr, void*(*start_routine)(void*), void* arg)) 参数thread: pthread_t 实际上是个无符号长整型,thread作为传出参数,若线程创建成功后,该线程的ID会被写入该参数中 attr:  线程的属性,一般传NULL。(之后我们会用它来设置线程分离属性) strt_routine: 线程处理函数,该函数就是子线程要做的事情。 arg:线程处理函数的参数,为线程处理函数传参。 返回值: 成功返回0,失败返回错误号。 注意:该错误号不是我们平时所说的 errno,线程中不能使用 perror() 函数。但我们可以使用下面这个函数:                                                                     char* strerror(int errnum)    该函数的返回值是 char* 类型的,所以可以通过它来打印与创建线程的错误号对应的错误信息。

退出线程

           #include                                                              void pthread_exit(void* retval );  参数:     retval : 用来保存一个错误信息,该参数必须指向全局变量或者堆内存。不能指向一个栈地址,因为该子线程退出时,该子线程对应的栈空间就被回收了。

阻塞等待线程退出,获取线程的退出状态,并且回收其PCB

                                            int pthread_join(pthread_t thread, void** retval); 参数: thread : 要回收的子线程的线程ID retval :传出参数,获取线程退出时携带的状态信息,和 pthread_exit() 函数的参数指向同一块内存地址。 返回值: 成功返回0,失败返回错误号。

线程ID

                                                     pthread_t pthread_self( void );                                  该函数总是执行成功,返回调用该函数的线程的线程ID

杀死(取消)线程

                                                  int pthread_cancel(pthread_t thread); 参数thread : 要杀死(取消)的子线程的线程ID 返回值: 成功返回 0,失败返回一个非零的错误号码。 注意事项: 在要杀死的子线程对应的处理函数的内部,必须做过一次系统调用,否则将不能将该子线程杀死。 如果不清楚什么是系统调用,可使用   pthread_testcancel() 函数来给子线程设置一个取消点,该函数就是个系统调用。  

线程分离

                                         int pthread_detach(pthread_t thread); 参数: thread : 要回收的子线程的线程ID 返回值: 成功返回0,失败返回错误号。 注意:在子线程中调用该函数后就不需要在主线程中使用 pthread_join() 函数了,设置线程分离后,子线程会自己回收自己的PCB,不用依赖父线程回收。不过有个极端的情况是,也许在子线程中还没来得及调用这个函数设置线程分离,线程就结束了,导致线程的PCB无法被回收。解决的办法是,直接利用 pthread_create() 函数的第二个参数,在创建线程的时候就对其设置线程分离的属性,下面就是该方法的介绍。

在创建线程时设置分离属性

1、 先根据参数创建一个 pthread_attr_t 类型的变量,如: pthread_attr_t  attr ;   2、线程属性操作函数       对线程属性变量的初始化:                                         int pthread_attr_init(pthread_attr_t* attr);       设置线程分离属性:                                        int pthread_attr_setdetachstate(pthread_attr_t* attr, int detachstate);                                 参数:                                          attr:  把属性设置给该参数                              detachstate: 线程属性,有两个用来设置分离状态的宏                                                       PTHREAD_CREATE_DETACHED (分离)                                                       PTHREAD_CREATE_JOINABLE(非分离)   3、释放线程资源函数                                      int pthread_attr_destroy(pthread_attr_t* attr);

以上函数的综合举例(代码)    

  1、不设置分离属性的创建线程的代码               该代码让主线程打印出其线程ID,然后循环五次打印信息,然后调用 pthread_join() ,在该处阻塞等待子线程结束。子线程也是打印出其线程ID,但虚幻五次打印信息时,每次间隔一秒钟,这样,可以保证子线程绝对比主线程结束的要慢。        当子线程结束时,主线程从 pthread_join() 处解除阻塞,最后打印出子线程退出的状态结束。 #include #include #include #include #include int global_exit_state = 777; //该全局变量用作子线程的退出状态 void* func(void* arg) //线程处理函数 { printf("child thread number: %lu ", pthread_self()); //打印子线程的线程ID int i = 0; for(; i < 5; i++) { sleep(1); printf("child i = %d ", i); } pthread_exit(&global_exit_state); //退出子线程 } int main() { //线程id变量 pthread_t pthid; //创建子线程 int ret = pthread_create(&pthid,NULL, func, NULL); if(ret != 0) { printf("error number: %d ", ret); // 根据错误码,打印错误信息 printf("%s ", strerror(ret)); } printf("parent thread id: %lu ", pthread_self()); //主线程的线程ID int i = 0; for(; i < 5; ++i) { printf("parent i = %d ", i); } void* ptr = NULL; pthread_join(pthid, &ptr); printf("exit status:%d ", *(int*)(ptr)); pthread_exit(NULL); } 运行结果为:   2、设置分离属性的创建线程的代码      设置线程分离后,子线程的PCB就不用主线程来释放了,它能够自己释放,所以不需要 pthread_join() 函数。 #include #include #include #include #include int global_exit_state = 777; void* func(void* arg) //线程处理函数 { printf("child thread number: %lu ", pthread_self()); int i = 0; for(; i < 5; i++) { sleep(1); printf("child i = %d ", i); } pthread_exit(&global_exit_state); } int main() { //创建一个子线程,线程id变量 pthread_t pthid; //初始化线程的属性 pthread_attr_t attr; pthread_attr_init(&attr); //设置线程分离的属性 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); //创建线程的时候设置线程分离 int ret = pthread_create(&pthid,&attr, func, NULL); if(ret != 0) { printf("error number: %d ", ret); // 根据错误码,打印错误信息 printf("%s ", strerror(ret)); } printf("parent thread id: %lu ", pthread_self()); int i = 0; for(; i < 5; ++i) { printf("parent i = %d ", i); } //释放资源 pthread_attr_destroy(&attr); printf("parent exit "); pthread_exit(NULL); } 运行结果: