linux--(1)线程的创建与终止

 

 

 # 线程基本概念

基本概念

进程是资源管理的最小单位,线程是程序执行的最小单位

进程都有自己的数据段、代码段和堆栈。占用资源比较多

 

所以演化出线程,花费更少的资源

 

线程与进程的关系是:线程是属于进程的

同一线程所产生的线程共享同一用户内存空间

一个进程至少需要一个线程作为他的指令执行体

进程管理者管理着资源(比如cpu,内存,文件)而将线程分配到某个cpu上执行

 

 

 理解一下比如:车道 主线路分出其他子线路

 

 

 

线程分类

 线程按其调度者可分为用户级线程内核级线程

    1.用户级线程:解决上下文切换的问题,由用户决定调度过程

    2.内核级线程:由内核调度机制调度

大多是都用并存

 

实现线程的库

linux ------- pthread

linux中需要链接线程库pthread 

 

线程标识

id 

pthread_t数据类型

 

 # 创建线程

 

 

 

完成案例:龟兔赛跑

#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>

 int main()
{

   int err;//定义错误存储
   pthread_t  rabbit,turtle;//定义线程标识符

//创建rabbit线程
   if((err=pthread_create(&rabbit,NULL,
                         th_fn,(void*)50))!=0){
  perror("pthread_create error");

return 0;
}                                                       

先讲一下这个创建线程几点

pthread_create(&rabbit,NULL,th_fn,(void*)50)
&rabbit是线程标识
NULL表示线程属性指针,表示没有这个
th_fn:线程运行函数
(void*)50:50转为指针,传递给线程运行函数的参数



-------------------------------------------------------------------
//drand48 返回服从均匀分布的·[0.0, 1.0) 之间的 double 型随机数。


源代码:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

//定义线程运行函数
void* th_fn(void *arg) //传入void*数值
{
    int distance=(long)arg; //强转为int,我的是64位的long
    int i;
    for (i =1; i <=distance; i++)
    {
        printf("%lx run %d\n", pthread_self(),i);
        int time=(int)(drand48()*100000);
        usleep(time);//微秒

    }
    return (void*)0; //返回指针 数值0
}

 int main()
{

   int err;//定义错误存储
   pthread_t  rabbit,turtle;//定义线程标识符

//创建rabbit线程
   if((err=pthread_create(&rabbit,NULL,
                         th_fn,(void*)50))!=0){
  perror("pthread_create error");}

//创建turtle线程
   if((err=pthread_create(&turtle,NULL,
                         th_fn,(void*)50))!=0){
  perror("pthread_create error");}

sleep(10);//先睡眠主线程,先运行子线程
printf("control thread id: %lx\n",pthread_self()); //以十六进制输出主控线程id
printf("fininshed!\n");


return 0;
}

                                                       

 

主线程结束后,碰到return 0就线程结束了,所以这里加一个sleep


运行

 

 

 

 

 

 交叉运行

distance为50到50,停止

 

 

 不能每次都这么好算sleep,sleep不好

所以接着换个方法 pthread_join

//主控线程调用pthread_join,自己阻塞
//直到rabbit和turtle线程结束才运行

pthread_join(rabbit,NULL);
pthread_join(turtle,NULL);

 

效果一样的

 

 

接下来案例二:对第四个参数传递具体结构体

 

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
//定义结构体类型:新结构体
typedef struct 
{
    char name[20];
    int time;
    int start;
    int end;
}RaceArg;


//定义运行函数
void* th_fn(void *arg){
    RaceArg *r=(RaceArg*)arg; //强转为结构体指针类型
    int i=r->start;
    for (; i <= r->end; i++)
    {
        printf("%s(%lx) running %d\n",r->name,pthread_self(), i);
        usleep(r->time);
    }

    return (void*)0;

}

int main(void)
{
    int err;
    pthread_t rabbit,turtle;

    RaceArg r_a =
    {
        "rabbit",(int)(drand48()*100000000),20,50};

    RaceArg t_a=
    {"turtle",(int)(drand48()*100000000),10,60};

    if ((err=pthread_create(&rabbit,NULL,th_fn,(void*)&r_a))!=0){
         perror("pthread_create error");
    }
    if ((err=pthread_create(&turtle,NULL,th_fn,(void*)&t_a))!=0){
         perror("pthread_create error");
    }

//主控线程调用pthread_join,自己阻塞,
//直到rabbit和turtle线程结束才运行
pthread_join(rabbit,NULL);
pthread_join(turtle,NULL);

printf("control thread id: %lx\n",pthread_self()); //以十六进制输出主控线程id
printf("fininshed!\n");

    return 0;
}

 

进程的内存分配

  • 线程各自的变量保存在线程各自的栈空间中,互相独立
  • 数据段的全局变量为共享资源,线程都可以访问更改,但是为线程不安全,需要把他变成线程安全。
  • 多线程编程中推荐使用局部变量。

 

 # 线程终止

线程终止的分类:

  1. 主动终止
  • 线程的执行函数中调用return语句
  • 调用pthread_exit()
  1. 被动终止
  • 线程可以被同一进程的其他线程取消,其他线程调用pthread_cancel(pthid)

线程终止的函数

#include <pthread.h>

int pthread_cancel(pthread_t tid);

void pthread_exit(void *retval);

int pthread_join(pthread_t th, void **thread_return);
//返回值:成功返回0,否则返回错误编号
  • pthread_cancel:
    • 线程可以被同一进程的其他线程取消,tid为被终止的线程标识符,pthread_cancel()无法回收资源
  • pthread_exit:
    • retval: pthread_exit调用者线程的返回值,可由其他函数和pthread_join来检测获取。
    • 线程退出时使用函数pthread_exit,是线程的主动行为。
    • 由于一个进程中的多个线程共享数据段,因此通常在线程退出后,退出线程所占用的资源并不会随线程结束而释放。所以需要pthread_join函数来等待线程结束,类似于wait系统调用。
  • pthread_join:
    • th:被等待线程的标识符。
    • thread_return:用户定义指针,用来存储被等待线程的返回值。

下面举几个例子:

案例1:二哥线程 id相加

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>

typedef struct
{
    int d1;
    int d2;
}Arg;

void* th_fn(void* arg)
{
    Arg* r=(Arg*)arg; //强转为结构体指针
    return (void*)(r->d1+r->d2); //输出是一个指针变量 返回指针
}

int main(int argc, char **argv)
{
    int err;
    pthread_t th;
    Arg r={20,50};
    
    if(0!=(err = pthread_create(&th,NULL,th_fn,(void*)&r)))
    perror("pthread_create error");
                

    //当返回为结构体指针
    int *result;
    pthread_join(th, (void**)&result); //指针的指针 用户定义指针,用来存储被等待线程的返回值。
    printf("result is %d\n",(int)result); //强转为int

    
    return 0;
}

 

 

 

20+50=70,

 

这是一种方法

//当返回为结构体指针
    // int *result;
    // pthread_join(th, (void**)&result); //指针的指针 用户定义指针,用来存储被等待线程的返回值。
    // printf("result is %d\n ,(int)result); //强转为int
    
    
    int result;
    pthread_join(th,(void*)&result);
    printf("result is %d\n",result);

 

效果一样,返回到result到上 结果70指针、int 变为70

然后void*变为指针

 

修改返回类型,返回结构体指针

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>

typedef struct
{
    int d1;
    int d2;
}Arg;

void* th_fn(void* arg)
{
    Arg* r=(Arg*)arg;
    //return (void*)(r->d1+r->d2); //输出是一个指针变量
    return (void*)r; //输出一个结构体变量指针
}

int main(int argc, char **argv)
{
    int err;
    pthread_t th;
    Arg r={20,50};
    
    if(0!=(err = pthread_create(&th,NULL,th_fn,(void*)&r)))
    perror("pthread_create error");
                
    /*                                
    int *result;
    pthread_join(th, (void**)&result); //给th_fn返回的指针变量赋值
    printf("result is %d\n",(int)result); 
    */
    /*或者
    int result;
    pthread_join(th, (void*)&result);
    printf("result is %d\n",result); 
    */
    
    //当返回为结构体指针
    int *result;
    pthread_join(th, (void**)&result);
    printf("result is %d\n",((Arg*)result)->d1+((Arg*)result)->d2); 
    
    return 0;
}

 

改进龟兔赛跑:

/*
 * pthread_creat2.c
 * 龟兔赛跑
 */


#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>

typedef struct
{
    char name[10];
    int time;
    int start; //起始点
    int end; //结束点
    
}RaceArg;

void* th_fn(void *arg)
{
    RaceArg *r = (RaceArg*)arg;
    
    for(int i=r->start; i<=r->end; ++i)
    {
        printf("%s(%lx) running %d\n",r->name,pthread_self(), i);
        usleep(r->time);
    }
    //return (void*)0;//pthread_exit((void*)0);
    return (void*)(r->end - r->start);
}

int main(int argc, char **argv)
{
    int err; //错误编码
    pthread_t rabbit,turtle; //定义线程标识符
    
    RaceArg r_a=
            {"rabbit",  (int)(drand48()*10000000),20,50};
    RaceArg t_a=
            {"turtle",  (int)(drand48()*10000000),10,60};

    if(0!=(err = pthread_create(&rabbit, NULL, th_fn, (void*)&r_a ))) //传入结构体指针
    { perror("pthread_create error"); }
    
    if(0!=(err = pthread_create(&turtle, NULL, th_fn, (void*)&t_a )))
    { perror("pthread_create error"); }

    int result;
    pthread_join(rabbit, (void*)&result);
    printf("rabbit race distance is %d\n", result);
    pthread_join(turtle, (void*)&result);
    printf("turtle race distance is %d\n", result);
    printf("race finished\n");
    /*
    pthread_join(rabbit,NULL);
    pthread_join(turtle,NULL);
    */
    printf("control thread ID: %lx\n",pthread_self());
    printf("finished!\n");
    
    return 0;
}

输出:

turtle(b660c460) running 10
rabbit(b6e0d460) running 20
rabbit(b6e0d460) running 21
rabbit(b6e0d460) running 22
rabbit(b6e0d460) running 23
rabbit(b6e0d460) running 24
rabbit(b6e0d460) running 25
rabbit(b6e0d460) running 26
rabbit(b6e0d460) running 27
rabbit(b6e0d460) running 28
rabbit(b6e0d460) running 29
rabbit(b6e0d460) running 30
rabbit(b6e0d460) running 31
rabbit(b6e0d460) running 32
rabbit(b6e0d460) running 33
rabbit(b6e0d460) running 34
rabbit(b6e0d460) running 35
rabbit(b6e0d460) running 36
rabbit(b6e0d460) running 37
rabbit(b6e0d460) running 38
rabbit(b6e0d460) running 39
rabbit(b6e0d460) running 40
rabbit(b6e0d460) running 41
rabbit(b6e0d460) running 42
rabbit(b6e0d460) running 43
rabbit(b6e0d460) running 44
rabbit(b6e0d460) running 45
rabbit(b6e0d460) running 46
rabbit(b6e0d460) running 47
rabbit(b6e0d460) running 48
rabbit(b6e0d460) running 49
rabbit(b6e0d460) running 50
rabbit race distance is 30
turtle(b660c460) running 11
turtle(b660c460) running 12
turtle(b660c460) running 13
turtle(b660c460) running 14
turtle(b660c460) running 15
turtle(b660c460) running 16
turtle(b660c460) running 17
turtle(b660c460) running 18
turtle(b660c460) running 19
turtle(b660c460) running 20
turtle(b660c460) running 21
turtle(b660c460) running 22
turtle(b660c460) running 23
turtle(b660c460) running 24
turtle(b660c460) running 25
turtle(b660c460) running 26
turtle(b660c460) running 27
turtle(b660c460) running 28
turtle(b660c460) running 29
turtle(b660c460) running 30
turtle(b660c460) running 31
turtle(b660c460) running 32
turtle(b660c460) running 33
turtle(b660c460) running 34
turtle(b660c460) running 35
turtle(b660c460) running 36
turtle(b660c460) running 37
turtle(b660c460) running 38
turtle(b660c460) running 39
turtle(b660c460) running 40
turtle(b660c460) running 41
turtle(b660c460) running 42
turtle(b660c460) running 43
turtle(b660c460) running 44
turtle(b660c460) running 45
turtle(b660c460) running 46
turtle(b660c460) running 47
turtle(b660c460) running 48
turtle(b660c460) running 49
turtle(b660c460) running 50
turtle(b660c460) running 51
turtle(b660c460) running 52
turtle(b660c460) running 53
turtle(b660c460) running 54
turtle(b660c460) running 55
turtle(b660c460) running 56
turtle(b660c460) running 57
turtle(b660c460) running 58
turtle(b660c460) running 59
turtle(b660c460) running 60
turtle race distance is 50
race finished
control thread ID: b6fe10b0
finished!
View Code

后续清理更新待写

 

posted @ 2021-12-01 11:09  halfup  阅读(334)  评论(0编辑  收藏  举报