线程

来源:互联网 发布:python np.empty 编辑:程序博客网 时间:2024/06/11 21:27

线程是进程内一个相对独立的、可调度的执行分支,有时被称为轻量级进程,是程序执行流的最小单元。也是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。在单个程序中同时运行多个线程完成不同的工作,称为多线程。下图即为多线程。
这里写图片描述
PCB1,PCB2,PCB3.PCB4是同一个进程内的线程,在同一地址空间内运行,但线程没有专门的线程描述符,Linux操作系统下是通过PCB模拟复用进程来描述线程。
由于同一个进程的多个线程共享同一地址空间,因此代码段和数据段都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问,各线程还共享以下进程资源和环境:
1:文件描述符表
2:每种信号的处理方式(SIG_IGN,SIG_DFI或者自定义的信号处理函数)
3:当前工作目录
4:用户id和组id
但以下资源为各进程私有:
1:线程id
2:上下文,包括各种寄存器的值,程序计数器和栈指针
3:栈空间
4:errno变量
5:信号屏蔽字
6:调度优先级
线程与进程的区别可以归纳为以下4点:
1)地址空间和其它资源(如打开文件):进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。
2)通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。
3)调度和切换:线程上下文切换比进程上下文切换要快得多。
4)在多线程OS中,进程不是一个可执行的实体。
下面实现一些关于线程的功能:
创建一个线程
在进程被创建时,系统会为其创建一个主线程,而要在进程中创建新的线程,则可以调用pthread_create函数。

#include<stdio.h>#include<pthread.h>#include<stdlib.h>void *thread_run(void *val){    printf("thread is:%u,pidis:%d\n",    pthread_self(),getpid());    return NULL;}int main(){    pthread_t tid;   if(pthread_create(&tid,NULL,thread_run,NULL)!=0)//创建线程   {       printf("creat thread error!\n");       return 0;   }   printf("main thread_run:pid is :%d,thread is:%u\n",getpid(),pthread_self());   sleep(2);   return 0;}

这里写图片描述
如果需要只终止某个线程而不终止整个进程,可以有三种方法:
1. 从线程函数return。这种方法对主线程不适用,从main函数return相当于exit。
2. 一个线程可以调用pthread_exit来终止自己
3. 线程还可以调用pthread_cancel终止同一进程中的另一个线程。进程取消,退出结果为-1.
注意这里不能使用exit函数来结束线程,因为他是用来结束进程的。

线程等待

#include<stdio.h>#include<pthread.h>#include<stdlib.h>void *thread_run(void *val){    printf("thread is: %u,pid is: %d\n",pthread_self(),getpid());    return NULL;}int main(){    pthread_t tid; if(pthread_create(&tid,NULL,thread_run,NULL)!=0)//创建线程   {       printf("creat thread error!\n");       return 0;   }   pthread_cancel(tid);//线程等待   void *ret;   pthread_join(tid,&ret);   printf("join new thread sucess,ret:%d\n",(int)ret);   return 0;}

这里写图片描述
thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:
1. 如果thread线程通过return返回,value_ptr所指向的单元里存放的是thread线程函数的返回值。
2. 如果thread线程被别的线程调用pthread_cancel异常终止掉,value_ptr所指向的单元里存放的是常数PTHREAD_CANCELED(pthread库中一般是-1)。
3. 如果thread线程是.自.己调.用pthread_exit终.止的,value_ptr所指向的单元存放的是传给pthread_exit的参数。 如果对thread线程的终止状态不感兴趣,可以传NULL给value_ptr参数 。

线程分离
在任何一个时间点上,线程是可结合的(joinable)或者是分离的(detached)。一个可结合的线程能够被其他线程收回其资源和杀死。在被其他线程回收之前,它的存储器资源(例如栈)是不释放的。相反,一个分离的线程是不能被其他线程回收或杀死的,它的存储器 资源在它终止时由系统自动释放。
默认情况下,线程被创建成可结合的。为了避免存储器泄漏,每个可结合线程都应该要么被显示地回收,即调用pthread_join;要么通过调用pthread_detach函数被分离。
如果一个可结合线程结束运行但没有被join,则它的状态类似于进程中的Zombie Process(僵尸进程),即还有一部分资源没有被回收,所以创建线程者应该调用pthread_join来等待线程运行结束,并可得到线程的退出代码,回收其资源。
由于调用pthread_join后,如果该线程没有运行结束,调用者会被阻塞,在有些情况下我们并不希望如此。例如,在Web服务器中当主线程为每个新来的连接请求创建一个子线程进行处理的时候,主线程并不希望因为调用pthread_join而阻塞(因为还要继续处理之后到来的连接请求),可将该子线程的状态设置为分离的(detached),如此一来,该线程运行结束后会自动释放所有资源。

#include<stdio.h> #include<pthread.h> #include<stdlib.h> void *thread_run(void *val) {     pthread_detach(pthread_self());     printf("%s\n",(char*)val);     return NULL; } int main() {     pthread_t tid;    if(pthread_create(&tid,NULL,thread_run,"other thread_run..")!=0)//creat thread    {        printf("creat thread error!\n");        return 0;    }    int ret = 0;    sleep(1);    if(0==pthread_join(tid,NULL))//wait success    {        printf("pthread wait success\n");        ret = 0;    }    else    {        printf("pthread wait failed!\n");        ret = 1;    }    return ret; }

这里写图片描述

原创粉丝点击