函数进程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
函数和进程
---------------------------------

原文地址:https://www.cnblogs.com/xinyuyuanm/p/3102350.html