函数进程APUE学习--Posix线程(1)
在写这篇文章之前,xxx已经写过了几篇关于改函数进程主题的文章,想要了解的朋友可以去翻一下之前的文章
线程(thread)----轻量级的进程、CPU调度的最小单位,相比较于进程,进程是分配资源的最小单位。
之前讲到的是多进程编程,这一部份要说的是如安在一个进程中实现多线程编程(当然将进程部份的内容放到一起,就可以实现多进程多线程编程)。POSIX(可移植性操纵系统接口)划定了可移植性的线程库pthread库<pthread.h>,这里面的函数需要在编译时加上-lpthread(-pthread)参数,pthread库中的类型以及函数是不透明的(把握如何使用,不必关怀如何实现)。
一个进程中至少有一个线程,从main()开始运行的线程称为 主线程(初始线程)。线程id类型pthread_t,可以使用pthread_self()返回,需要注意的是,线程id只是在一个进程内有效(进程id在整个系统中有效);使用pthread_equal()比较两个线程的id是否相称。
pthread_t pthread_self(void); int pthread_equal(pthread_t tid1, pthread_t tid2);
线程创立的创立使用pthread_create()函数:
int pthread_create(pthread_t *tidp, const pthread_attr_t *attr, void *(*start_rtn)(void*), void *arg);
函数的第一个参数tidp,是一个出参,用来带回被创立线程的tid;第二个参数attr设置的线程属性(前面说明),默许属性传NULL即可;第三个参数start_rtn是一个函数指针,是被创立线程的进口函数(新线程从该函数开始运行至该函数结束);第四个参数arg是start_rtn函数的参数;该函数调用成功返回0,否则返回出错编码(不使用errno全局变量)。几点需要注意:
1.受OS调度影响,被创立的线程处于就绪状态,故创立线程的线程往往是先被调用。
2.统一进程中的多个线程共享内存资源,故多个线程对进程中的所有变量都是共享的(但要注意该变量的生存期和作用域)。
3.只要进程(主线程)退出,其余未结束的线程都随之结束了(进程结束资源也就没了)
4.统一进程中的多个线程共享文件描述符,并非复制一份。
5.统一进程中的多个线程共享进程的信号屏蔽字,但新线程的未决信号集讲被清空。
进程退出的方式:从start_rtn返回;自身调用pthread_exit()函数;被统一个进程中的其他线程取消。先来看pthread_exit()函数和与之配套的pthread_join()函数:
void pthread_exit(void *rval_ptr); int pthread_join(pthread_t thread, void **rval_ptr);
pthread_exit()函数相似于进程中的exit()函数,线程直接终止,并将rval_ptr参数作为线程的返回值。pthread_join()的功能相似进程的waitpid(pid)函数,阻塞等待指定的线程退出并接受返回值,参数是void **类型,是一个出参参数。
线程中也有相似进程atexit()注册清理操纵的函数,pthread_cleanup_push() pthread_cleanup_pop()注册线程的清理函数。
void pthread_cleanup_push(void (*rtn)(void *), void *arg); void pthread_cleanup_pop(int execute);
注册的函数有两个参数,一个是函数指针,一个是该函数接收的参数。第二个函数在执行后会设置之前注册的函数的执行状态,如果execute为0则不执行否则执行,需要注意的是,这两个函数必须是在一个函数内成对出现(具体实现应该是带括号的宏定义),但可以斟酌放到pthread_exit()后。
再来说下pthread_cancel()函数,它和pthread_exit()都能使一个线程退出,不同是后者是使线程本身退出,而前者是使统一进程中的其他线程退出。
int pthread_cancel(pthread_t tid);
该函数的道理是:向tid线程发送SIGCANCEL信号(这个信号在kill -l中查询不到)。只是发送一个信号作为请求,但指定的线程是否退出何时退出pthread_cancel()其实不关怀,这就涉及到一个问题,一个线程在接收到SIGCANCEL信号时何时退出,有个取消点的概念。大部份的pthread函数以及阻塞的系统调用都是取消点,增加设置取消点的函数是pthread_testcancel():
void pthread_testcancel(void);
通过这个函数可以设置取消点。取消点涉及到可取消状态和取消类型的的概念,相关操纵如下:
int pthread_setcancelstate(int state, int *oldstate); int pthread_setcanceltype(int type, int *oldtype);
分离用来设置取消状态和取消类型。取消状态包括PTHREAD_CANCEL_ENBALE可以被取消 PTHREAD_CANCEL_DISABLE不允许被取消;取消类型包括PTHREAD_CANCEL_DEFERRED直到取消点才终止 PTHREAD_CANCEL_ASYNCHRONOUS当即终止(这个在很多平台下是不好用的)
再介绍一下其他的线程属性,线程属性的类型是pthread_attr_t类型,类型的初始化和销毁分离是pthread_attr_init() pthread_attr_destroy()两个函数:
int pthread_attr_init(pthread_attr_t *attr); int pthread_attr_destroy(pthread_attr_t *attr);
线程的属性包括:分离属性 绑定属性 线程栈属性等等,这里我们只说下分离属性(其余的用不到)。如果一个线程被分离了,那么创立它的线程即使调用了pthread_join()也不能等待并接受该线程的返回值。设置分离属性有两种方法,第一种是直接调用pthread_detach()函数,第二其中是将线程属性传入到pthread_create()函数中。
int pthread_detach(pthread_t tid); int pthread_attr_getdetachstate(const pthread_attr_t * attr, int *detachstate); int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
pthread_detach()函数使tid线程分离,前面两个函数操纵的是线程属性的结构,detachstate的值可所以PTHREAD_CREATE_JOINABLE不分离(默许的) PTHREAD_CREATE_DETACHED分离。这两种方法的区别是,第一种用于线程已被创立后分离,另一种用于创立前设置。
文章结束给大家分享下程序员的一些笑话语录:
这年头的互联网真是娱乐了中国,网民们从各种各样的“门”里钻来钻去,又有好多“哥”好多“帝”,值得大家品味不已……网络经典语录,关于IT与互联网,经典与您分享!
---------------------------------
原创文章 By
函数和进程
---------------------------------