linux操作系统之线程

(1)线程(LWP)   可使用命令查看指定线程的LWP号:  ps  -Lf pid

            1)light weigh process(轻量级进程),本质上仍然是进程

                       进程:独立的地址空间,拥有PCB,最小分配资源单位,内存分配资源以进程为标准。

                       线程:没有独立的地址空间(共享),拥有PCB,最小的执行单位,CPU分配时间轮片是以线程为标准。

            2)线程和进程的联系和区别

                  1>线程也有PCB,创建线程使用的底层函数和进程一样,都是clone。

                  2>从内核里看进程和线程都是一样的,都有各自不同的PCB,但PCB中指向内存的三级页表是相同的(类似于指向相同内存的指针,指针不同,但是内存相同)。

                       三级映射:进程PCB--->页目录(4kb)-->页表---->物理页面---->内存单元

                              

                  3>进程可以退变成线程。

                  4>线程可以看做寄存器和栈的集合

           3)线程资源和优缺点

                     1)共享资源

                               文件描述符  信号处理方式   工作目录  用户id和组id      内存地址空间(除栈空间和errno变量)

                    2)独享资源

                              线程id   处理器现场和栈指针(内核栈)和独立的栈空间(用户栈 )  errno变量    信号屏蔽字  调度优先级

                    3)线程优缺点

                             优点:提高程序并发性  开销小(针对于进程)  数据通信共享数据方便(进程:IPC通信)

                             缺点:使用库函数,不稳定   调试编译困难,gdb不支持(出现在gdb之后)   对信号支持不好

(2)线程控制原语

           1)获取线程id:  pthread_t pthread_self(void);                     ---->对应进程getpid()

                         pthread_t  pthread_self(void);            返回值:成功 0     失败  无

               pthread_t:为linux下的无符号整数(%lu)

               线程ID为进程内部,识别标志,两个进程之间线程id允许相同。

         2)创建一个新线程 :pthread_create                                                --->对应进程的fork()

                    int pthread_create(pthread_t *thtrad,const pthread_attr_t *attr,void*(*start_routinue)(void *),void *arg);

        返回值   成功:0     失败:错误号(linux环境下线程的特点:失败均返回错误号,不能使用perror,而应该使用sterror函数

         参数              1:保存系统为分配的线程id

                               2:通常设置为NULL,表示使用线程的默认属性(可使用具体参数修改该参数)

                               3:函数指针,指向线程主函数(线程体)。函数运行结束,则线程结束。

                               4:主函数执行期间所使用的参数。

          使用pthread_create循环创建多个线程,每个线程打印自己是第几个被创造的线程

                1>实现和结果

               

                           

                    直接将整形转化为指针类型,如果是32位的操作系统,直接转换。如果是64位的操作系统,则是小端转大端问题,前头补零,数据不变化。

             2>代码修改:(换成取地址,符合我们正常的理解,结果有问题

                  

                    

                  如果是取地址的话,则线程去i的时候可能其他的线程也来了,此时两个线程公用全局变量,使得两个i值混乱。可以直接利用两个线程之间不共享栈的特点,直接采用值传递,而不是址传递。

           3)单个进程退出:pthread_exit函数

                  void  pthread_exit(void* retval)  参数:retval 表示线程退出状态,通常传NULL

          在多线程中 exit ,return ,pthread_exit的区别:

                 exit:进程中的所有线程退出,在线程中应该禁止使用exit.

                 return:返回到调用者那里,继续执行下一步程序。

                pthread_exit:退出单个线程

          结论:多线程环境中,应该尽量不用或者少用exit函数,取而代之用pthread_exit函数。pthread_exit或者return返回的指针所指向的内存必须是全局或者malloc分配的(不同线程不共享栈)

          4)阻塞等待线程退出,获取线程退出状态 :pthread_join                         ---->对应进程中的waitpid()

                    int  pthread_join(pthread_t thread,void **retval);     成功:0  失败:错误号

             参数:线程id  ,retavl:储存线程结束状态。

        5)线程分离:pthread_detach(常用与网路和多线程服务器)

                   int   pthread_detach(pthread_t thread)       成功:0  失败:错误号

                   线程分离:线程主动与主控线程断开联系。线程结束后,其退出状态不由其他线程获取,而是自己主动释放(不会产生僵尸进程)(也可以通过pthread_create 通过设置参数2实现线程分离)

                使用了线程分离的线程不能够在使用pthread_join,这样调用返回EINVAL错误

       6)杀死(取消)线程:pthread_cancel函数                    --->进程的kill函数

                 int pthread_cancel(pthread_t thread);           成功:0  失败:错误号

           注意:线程的取消和杀死并不是实时的,而是有一定的延时性,需要等待线程到底某个取消点或者检查点(通常是系统调用,可通过 man 7 pthread查看取消点列表,也可以通过pthread_testcancel()函数来自行设置一个取消点)

        当我们对一个已经取消的线程使用pthread_join时,返回值是-1.

         终止线程的方式:

                       1>线程主函数return 返回,不适用于主控线程。

                       2>一个线程调用pthread_cancel终止同一个进程中的另一个线程。

                       3>线程可以调用pthread_exit终止自己。

猜你喜欢

转载自blog.csdn.net/xx18030637774/article/details/82345106