线程基础(一)

来源:互联网 发布:天津网络送花 编辑:程序博客网 时间:2024/06/05 14:31

线程的概念:

#线程概念
1.进程是资源管理的最小单位,线程是程序运行的最小单位
2.每个进程有自己的数据段代码段堆栈空间,线程通常叫做轻量级进程,它包含独立的栈和cpu寄存器状态,线程是进程的一条执行路径,每个线程共享其所在进程的所有资源(所以线程基本不占用资源的,开销很小),包括打开的文件,内存页面,信号标识及动态分配的内存等。
3.因为线程和进程比起来很小,所以相对来说,线程花费更少的cpu资源
4.在操作系统设计上,从进程演化出线程,最主要的目的就是更好的支持多处理器,并且减少进程上下文的切换的开销。

我们通过下面这个(代码)图示来看线程的内存布局:
示例代码:
        
#include<stdio.h>#include<stdlib.h>#include<pthread.h>typedef struct {    char name[20];    int time;    int start;     int end;}RaceArg;void* th_fd(void *arg){    RaceArg *r = (RaceArg *)arg;//强制转换    int i = r->start;    for(; i < r->end; ++i)    {        printf("%s (%lx) run %d\n", r->name, pthread_self(), i);        usleep(r->time);    }//    return (void *)0;    //return (void*)(r->end - r->start);    return (void *)r;}int main(void){    int err;    pthread_t rabbit, turtle;    RaceArg r_a = {"rabbit", (int)drand48()*1000000000, 10, 50};    RaceArg t_a = {"turtle", (int)drand48()*1000000000, 20, 60};    if((err = pthread_create(&rabbit, NULL, th_fd, (void *)&r_a)) != 0)    {        perror("pthread_create rabbit error");        exit(1);    }    if((err = pthread_create(&turtle, NULL, th_fd, (void *)&t_a)) != 0)    {        perror("pthread_create turtle error");        exit(1);    }    int *result;//这里必须要用指针,因为下面强转为结构体类型,如果定义成整形,内存不匹配,断错误。    pthread_join(rabbit, (void **)&result);    printf("rabbit destance = %d\n", ((RaceArg *)result)->end-((RaceArg *)result)->start);    pthread_join(turtle, (void **)&result);    printf("turtle destance = %d\n", (((RaceArg *)result)->end)-((RaceArg *)result)->start);    printf("control thread %lx run finished!\n", pthread_self());    return 0;}
这里是龟兔线程赛跑的代码,运行结果这里为了篇幅就不赘余了,你可以运行一下。这里两个线程分别执行自己的局部变量的增长。
我通过一个图示来说明线程和变量的关系:

这里就可以说明线程虽然共享进程的所有资源。但是每个线程都有自己独立的栈空间。

线程分类:

1.线程按照调度者,可以分为用户级线程和内核级线程(一个用户级线程都是和内核级线程绑定的)
用户级线程:主要是进程上下文切换的问题,其调度过程由用户决定
内核级线程:由内核调度机制实现
2.默认状态下用户级线程和内核级线程是一对一绑定的,也可以一对多,但是实时性比较差
3.现在的操作系统都是用户级线程和内核级线程并存
4.当CPU分配给现成的额时间片用完时,线程返回进入就绪状态,等待cpu调度,再次运行,和进程类似

下面通过一个程序来看一下子线程和主控线程之间的关系和编程时需要注意的问题:
示例代码:
#include<stdio.h>#include<stdlib.h>#include<math.h>#include<pthread.h>//使用线程模拟龟兔赛跑//void*  th_fd(void *arg)//通用指针{    int destance = (int)arg;    int i ;    for(int i =1; i < destance; ++i)    {        printf("%lx run %d\n", pthread_self(), i);        int time = (int)(drand48()*100000);        usleep(time);//微秒    }    return (void *)0;}int main(void){    pthread_t robbit, turtle;//定义线程标识符    int err;    //创建robbit线程    if((err = pthread_create(&robbit, NULL, th_fd, (void *)50)) != 0)    {        perror("pthread_create robbit error");        exit(1);    }    //创建turtle线程    if((err = pthread_create(&turtle, NULL, th_fd, (void *)50)) != 0)    {        perror("pthread_create turtle error");        exit(1);    }    //主控线程的id    //为了保证两个子线程正常运行,得让主控线程阻塞,等待子线程运行。    //方法1:    //sleep(10);    //方法2:调用join的线程会自动阻塞,谁调用谁阻塞,等待传入的线程标识符结束,才可能再次运行。    pthread_join(robbit, NULL);    pthread_join(turtle, NULL);    printf("control thread id = %lx\n", pthread_self());}
正如程序中注释说的那样,倘若你没有调用pthread_join那么两个子线程就不会显示运行,究竟是为什么呢?
因为创建了两个线程以后,该程序进程有三个线程,这时候现成的运行顺序是由系统调度的,我们无法确定,这时候主控县城先运行了,所以当主控线程运行完毕,所以线程都要强制释放清空,所以你会看到两个子线程没有运行。

线程终止:

pthread_cancle(pthread_t tid)被同一个进程中的其他线程终止
pthread_exit(void *retval)参数是该函数调用者线程的返回值可以由其他线程或者pthread_join获取。


原创粉丝点击