浅析Linux之线程

目录

概述

程序

进程

线程

区别

特点

线程共享资源

线程非共享资源

线程的优缺点

线程号      

线程号

查看是否有线程函数列表

命令

安装

获取线程号pthread_self函数

概述

程序

可执行文件

进程

操作系统分配资源的最小单位

线程

CPU调度的最小单位

所以,线程是轻量级的进程(LWP:light weightprocess),在Linux环境下线程的本质仍是进程。为了让进程完成一定的工作,进程必须至少包含一个线程。

浅析Linux之线程_第1张图片

区别

  • 内核不区别,本质是进程(线程是轻量级的进程的原因
  • 用户区别,进程有进程号,系统唯一;线程有线程号,进程中唯一
  • 线程依赖进程,进程结束,线程也会结束。

特点

线程共享资源

        1)文件描述符表

        2) 每种信号的处理方式

        3) 当前工作目录

        4) 用户ID和组ID 内存地址空间
        (.text/.data/.bss/heap/共享库)


线程非共享资源

        1) 线程id

        2) 处理器现场和栈指针(内核栈)

        3) 独立的栈空间(用户空间栈)

        4) errno变量

        5) 信号屏蔽字

        6)调度优先级


线程的优缺点

        优点: Ø 提高程序并发性 Ø 开销小 Ø 数据通信、共享数据方便

        缺点: Ø 库函数,不稳定 Ø 调试、编写困难、gdb不支持 Ø 对信号支持不好 优点相对突出,缺点均不是硬伤。Linux下由于实现方法导致进程、线程差别不是很大。

线程号      

        就像每个进程都有一个进程号一样,每个线程也有一个线程号。进程号在整个系统中是唯一的,但线程号不同,线程号只在它所属的进程环境中有效。 进程号用 pid_t 数据类型表示,是一个非负整数。线程号则用 pthread_t 数据类型来表示,Linux 使用无符号长整数表示。 有的系统在实现pthread_t 的时候,用一个结构体来表示,所以在可移植的操作系统实现不能把它做为整数处理

线程号

查看是否有线程函数列表

命令

man -k pthread

如果出现一堆东西说明可用如果没有就进行安装

安装

sudo apt-get install manpages-posix-dev

获取线程号pthread_self函数

就像每个进程都有一个进程号一样,每个线程也有一个线程号。进程号在整个系统中是唯一的,但线程号不同,线程号只在它所属的进程环境中有效。 进程号用 pid_t 数据类型表示,是一个非负整数。线程号则用 pthread_t 数据类型来表示,Linux 使用无符号长整数表示。 有的系统在实现pthread_t 的时候,用一个结构体来表示,所以在可移植的操作系统实现不能把它做为整数处理

#include 

pthread_t pthread_self(void);
功能:
    获取线程号。
参数:
    无
返回值:
    调用线程的线程 ID 
#include 
#include 
int main()
{
    pthread_t tid = pthread_self();
    printf(" %ld\n", tid);
    return 0;
}

注意:进行编译时需要链接库,直接用make进行编译会出现一下情况

线程的创建

#include 

int pthread_create(pthread_t *thread,
                    const pthread_attr_t *attr,
                    void *(*start_routine)(void *),
                    void *arg );
功能:
    创建一个线程
参数:
    thread:线程标识符地址。
    attr:线程属性结构体地址,通常设置为 NULL。
    start_routine:线程函数的入口地址。
    arg:传给线程函数的参数。
返回值:
    成功:0
    失败:非 0
#include 
#include 
#include 

void *fun(void *arg)
{
    pthread_t tid;
    while(1)
    {
        tid = pthread_self();
        printf("新创建的线程 = %ld\n", tid);
        sleep(1);
    }
}

int main()
{
    pthread_t tid, tid1;

    pthread_create(&tid1, NULL, fun, NULL);
    
    while(1)
    {
        pthread_t tid = pthread_self();
        printf("进程自带线程: %ld\n", tid);
        sleep(1);
    }
    return 0;
}

浅析Linux之线程_第2张图片

线程的通信

全局变量

定义一个局部变量,在其中一个线程中执行++操作,在另一个线程中进行printf输出,可发现输出的变量在执行++操作

局部变量

值传递

将值作为形参传入函数,但需要进行类型转换

地址传递

将值的地址作为参数传入函数,对其处理时也需要进行类型转换

#include 
#include 
#include 

//int num=0;
#if 0
//值传递
void *fun1(void *arg)
{
    int num=(int)arg;
    while(1)
    {
        printf("fun1 = %d\n", num);
        sleep(1);
    }
}
void *fun2(void *arg)
{
    int num=(int)arg;
    while(1)
    {
        num++;
        printf("fun2 = %d\n", num);
        sleep(1);
    }
}

int main()
{
    int num=0;
    pthread_t tid,tid1,tid2;
    pthread_create(&tid1,NULL,fun1,(void *)num);
    pthread_create(&tid2,NULL,fun2,(void *)num);

    while(1);
    return 0;
}
#endif
//地址传递
void *fun1(void *arg)
{
    while(1)
    {
        printf("fun1 = %d\n", *(int*)arg);
        sleep(1);
    }
}
void *fun2(void *arg)
{
    while(1)
    {
        (*(int*)arg)++;
        printf("fun2 = %d ************\n",*(int*)arg);
        sleep(1);
    }
}
int main()
{
    int num=0;
    pthread_t tid,tid1,tid2;
    pthread_create(&tid2,NULL,fun2,(void *)&num);
    pthread_create(&tid1,NULL,fun1,(void *)&num);

    while(1);
    return 0;
}

回收线程资源

pthread_join

特点

  • 等待并回收线程资源
  • 默认阻塞;回收线程,阻塞解出,一次调用只能回收一个线程

格式

#include 

int pthread_join(pthread_t thread, void **retval);
功能:
    等待线程结束(此函数会阻塞),并回收线程资源,类似进程的 wait() 函数。如果线程已经结束,那么该函数会立即返回。
参数:
    thread:被等待的线程号。
    retval:用来存储线程退出状态的指针的地址
返回值:
    成功:0
    失败:非 0

使用

#include 
#include 
#include 
#include 
int num =0;
void *pthid1_callback(void *agr)
{
    int a=0;
    for(int i=0;i<5;i++)
    {
        num++;
        printf("i am pth 1 run\n");
        sleep(1);
    }
} 
void *pthid2_callback(void *agr)
{
    for(int i=0;i<2;i++)
    {
    printf("i am pth 2 run num=%d\n",num);
    sleep(1);
    }
} 
int main(int argc, char *argv[])
{
    pthread_t pthid1,pthid2;
    //创建线程
    pthread_create(&pthid1,NULL,pthid1_callback,NULL);
    pthread_create(&pthid2,NULL,pthid2_callback,NULL);
    pthread_join(pthid1,NULL);//等5s 阻塞
    pthread_join(pthid2,NULL);
    return 0;
}

pthread_detach

功能及特点

  • 回收线程资源(系统回收)——线程分离
  • 默认非阻塞,一次调用可分离一个线程让该线程资源被系统回收
  • 使用时要保证进程不退出

格式

#include 

int pthread_detach(pthread_t thread);
功能:
    使调用线程与当前进程分离,分离后不代表此线程不依赖与当前进程,线程分离的目的是将线程资源的回收工作交由系统自动来完成,也就是说当被分离的线程结束之后,系统会自动回收它的资源。所以,此函数不会阻塞
参数:
    thread:线程号。
返回值:
    成功:0
    失败:非0

线程的退出和取消

pthread_exit

#include 

void pthread_exit(void *retval);
功能:
    退出调用线程。一个进程中的多个线程是共享该进程的数据段,因此,通常线程退出后所占用的资源并不会释放。
参数:
    retval:存储线程退出状态的指针。
返回值:无
#include 
#include 
#include 
void *callback(void *arg)
{
    int i=0;
    while(1)
    {
        printf("hello world\n");
        sleep(1);
        if(50 == i++)
        pthread_exit(NULL);
    }
     return NULL;
} 
int main(int argc, char *argv[])
{
    pthread_t pthid;
    pthread_create(&pthid,NULL,callback,NULL);
    printf("join\n");
    pthread_join(pthid,NULL);
    printf("join ok\n");
    return 0;
}

pthread_cancel

#include 

int pthread_cancel(pthread_t thread);
功能:
    杀死(取消)线程
参数:
    thread : 目标线程ID。
返回值:
    成功:0
    失败:出错编号
void *thread_cancel(void *arg)
{
    while (1)
    {
        pthread_testcancel(); //设置取消点
    } 
    return NULL;
} 
int main()
{
    pthread_t tid;
    pthread_create(&tid, NULL, thread_cancel, NULL); //创建线程
    sleep(3); //3秒后
    pthread_cancel(tid); //取消tid线程
    pthread_join(tid, NULL);
    return 0;
}

你可能感兴趣的:(linux,c语言,开发语言,物联网)