首页 > 其他分享 >07.多线程的概述

07.多线程的概述

时间:2024-03-17 19:30:41浏览次数:30  
标签:include 07 -- void int 线程 pthread 概述 多线程

1.线程的概述

进程--是我们程序的执行实例,进程在执行的时候,真正执行的就是进程中的线程,进程只是提供了线程执行的资源(PCB)。---进程包含线程

进程:进程指正在运行的程序。确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能。

线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。

例如:

进程---老板---》分配工作,分配资源的

线程--各部门工作人员--》干活,共用进程中的资源(PCB--进程控制块)

进程是分配资源的最小单位---重要

线程是程序执行的最小单元--重要

严格意义上,线程也是进程,他只是和进程不同的点,线程属于进程的,那么线程是不是可以共享进程的资源呢?---可以的

总结以下进程和线程的区别和联系:

不同线程是否可以共享全部的资源??

线程之间共享的内容:

1.代码

2.数据(进程中的)

3.进程空间

4.文件

不共享的内容:

1.寄存器

2.栈--线程中临时开辟的区域

线程和进程的比较:

多线程的应用场景:

应用主要方向---高并发服务器

QQ聊天室---

1.可以使用多进程编写

2.可以使用多线程编写

线程不属于系统中标准库的一部分,现成的使用需要调用其他的跟线程相关的库函数,如果需要去查看线程相关的函数定义,需要安装以下内容

在线手册安装:
sudo apt-get update
sudo apt-get install manpages-posix manpages-posix-dev
如果以上方法不行,尝试以下方法:

manpages 包含 GNU/Linux 的基本操作: 
sudo apt-get install manpages

manpages-dev 包含 GNU/Linux 的基本操作API: 
sudo apt-get install manpages-dev

manpages-posix 包含 POSIX 所定义公用程序的方法: 
sudo apt-get install manpages-posix

manpages-posix-dev 包含 POSIX 的 header files 和 library calls 的用法:
sudo apt-get install manpages-posix-dev

在许多经典的操作系统教科书中, 总是把进程定义为程序的执行实例, 它并不执行什么, 只是维护应用程序所需的各种资源, 而线程则是真正的执行实体。 所以,线程是轻量级的进程(LWP: light weight process) , 在 Linux 环境下线程的本质仍是进程。 为了让进程完成一定的工作, 进程必须至少包含一个线程。

线程是进程的一个实体, 是 CPU 调度和分派的基本单位, 它是比进程更小的能独立运行的基本单位。

线程自己基本上不拥有系统资源, 只拥有一点在运行中必不可少的资源(如程序计数器, 一组寄存器和栈) , 但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

线程共享的资源和线程非共享的

共享资源:

1) 文件描述符表

2) 每种信号的处理方式

3) 当前工作目录

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

非共享资源:

1) 线程 id

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

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

4)errno 变量

5) 信号屏蔽字

6) 调度优先级

线程的优缺点(了解)

优点:

  • 提高程序并发性
  • 开销小 --同一个进程中的不通线程共享资源
  • 数据通信、 共享数据方便

缺点:

  • 库函数, 不稳定
  • 调试、 编写困难、 gdb 不支持
  • 对信号支持不好

优点相对突出, 缺点均不是硬伤。 Linux 下由于实现方法导致进程、 线程差别不是很大。

2.线程的创建

线程号

进程号在整个系统中是唯一的, 但线程号不同, 线程号只在它所属的进程环境中有效。

线程号则用 pthread_t 数据类型来表示,Linux 使用无符号长整数表示

获得线程号pthread_self():
#include <pthread.h>
pthread_t pthread_self(void);
功能:
获取线程号。
参数:
无
返回值:
调用线程的线程 ID 
线程的创建

建议大家联系以下我们之前学习的RT_THREAD操作系统

#include <pthread.h>
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
start_routine所指向的函数定义格式
void *xxxxx(void *arg);

不同的线程也是可以执行相同的函数,也可以执行不同的函数

创建一个线程:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <pthread.h>
/*
pthread_t pthread_self(void);--线程ID
*/

void *Pthread_func01(void *argv)
{
    pthread_t pth_id;
    printf("已经进入Pthread_func01\n");
    // pth_id=pthread_self();
    // printf("rev-->%s; pth_id-->%ld\n",(char *)argv,pth_id);
    printf("pth_id-->%lu\n",pthread_self());
    printf("rev-->%s\n",(char *)argv);
    // sleep(2);
    return NULL;
}

void *Pthread_func02(void *argv)
{
    printf("已经进入Pthread_func02\n");

    return NULL;
}

/*
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg );--创建线程


*/

int main(void)
{
    pthread_t p_th1;
    int ret;

    ret=pthread_create(&p_th1,NULL,Pthread_func01,"hello world");
    if(ret!=0)
    {
        printf("线程创建失败\n");
        // exit(-1);
    }
    getchar();
    return 0;
}

创建多个线程,使用同一个线程执行函数:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <pthread.h>
/*
pthread_t pthread_self(void);--线程ID
*/

void *Pthread_func01(void *argv)
{
    pthread_t pth_id;
    printf("已经进入Pthread_func\n");
    // pth_id=pthread_self();
    // printf("rev-->%s; pth_id-->%ld\n",(char *)argv,pth_id);
    printf("pth_id-->%lu\n",pthread_self());
    printf("rev-->%s\n",(char *)argv);
    // sleep(2);


    return NULL;
}

void *Pthread_func02(void *argv)
{
    printf("已经进入Pthread_func02\n");

    return NULL;
}

/*
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg );--创建线程

*/

int main(void)
{
    pthread_t p_th1,p_th2;
    int ret;

    ret=pthread_create(&p_th1,NULL,Pthread_func01,"p_th1:hello");
    if(ret!=0)
    {
        printf("线程1创建失败\n");
        // exit(-1);
    }

    ret=pthread_create(&p_th2,NULL,Pthread_func01,"p_th2:hello");
    if(ret!=0)
    {
        printf("线程2创建失败\n");
        // exit(-1);
    }
    getchar();
    return 0;
}

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <pthread.h>
/*
pthread_t pthread_self(void);--线程ID
*/

void *Pthread_func01(void *argv)
{
    int cout=0;
    pthread_t pth_id;
    printf("pth_id-->%lu\n",pthread_self());
    printf("rev-->%s\n",(char *)argv);
    for(int i=0;i<5;i++)
    {
        sleep(1);
        cout++;
        printf("Pthread_func01 running is %d s\n",cout);
    }
    // sleep(2);
    return NULL;
}

void *Pthread_func02(void *argv)
{
    int cout=0;
     pthread_t pth_id;
    printf("pth_id-->%lu\n",pthread_self());
    printf("rev-->%s\n",(char *)argv);

     for(int i=0;i<7;i++)
    {
        sleep(1);
        cout++;
        printf("Pthread_func02 running is %d s\n",cout);
    }
    // sleep(2);
    return NULL;
}

/*
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg );--创建线程
*/

int main(void)
{
    pthread_t p_th1,p_th2;
    int ret;
    ret=pthread_create(&p_th1,NULL,Pthread_func01,"p_th1:hello");
    if(ret!=0)
    {
        printf("线程1创建失败\n");
        // exit(-1);
    }
    
    ret=pthread_create(&p_th2,NULL,Pthread_func02,"p_th2:hello");
    if(ret!=0)
    {
        printf("线程2创建失败\n");
        // exit(-1);
    }
    while(1);
    // getchar();
    return 0;
}

查看线程数量

ps -ajx |grep a.out

ps -T p id

ps -T p id |wc -l 查看进程下的线程数

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

#include <pthread.h>
/*
pthread_t pthread_self(void);--线程ID
*/

void *Pthread_func01(void *argv)
{
    int cout=0;
    pthread_t pth_id;
    printf("pth_id-->%lu\n",pthread_self());
    printf("rev-->%s\n",(char *)argv);
    for(int i=0;i<5;i++)
    {
        sleep(1);
        cout++;
        printf("Pthread_func01 running is %d s\n",cout);
    }
    // sleep(2);
    return "func01_exit";
}

void *Pthread_func02(void *argv)
{
    int cout=0;
     pthread_t pth_id;
    printf("pth_id-->%lu\n",pthread_self());
    printf("rev-->%s\n",(char *)argv);

     for(int i=0;i<7;i++)
    {
        sleep(2);
        cout++;
        printf("Pthread_func02 running is %d s\n",cout);
    }
    // sleep(2);
    return "func02_exit";
}

/*
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg );--创建线程
*/
int main(void)
{
    pthread_t p_th1,p_th2;
    int ret;

    ret=pthread_create(&p_th1,NULL,Pthread_func01,"p_th1:hello");
    if(ret!=0)
    {
        printf("线程1创建失败\n");
        // exit(-1);
    }
    ret=pthread_create(&p_th2,NULL,Pthread_func02,"p_th2:hello");
    if(ret!=0)
    {
        printf("线程2创建失败\n");
        // exit(-1);
    }

//int pthread_join(pthread_t thread, void **retval);

    char *func_str;
    pthread_join(p_th1,&func_str);
     printf("p_th1-->%s\n",(char *)func_str);

    pthread_join(p_th2,&func_str);
     printf("p_th2-->%s\n",(char *)func_str);

    // while(1);
    // getchar();
    return 0;

线程分离:

线程属于进程的,分离--》将当前的线程和进程进行分离,分离之后的线程就是交给系统进行回收

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

#include <pthread.h>
/*
pthread_t pthread_self(void);--线程ID
*/

void *Pthread_func01(void *argv)
{
    int cout=0;
    pthread_t pth_id;
    printf("pth_id-->%lu\n",pthread_self());
    printf("rev-->%s\n",(char *)argv);
    for(int i=0;i<5;i++)
    {
        sleep(1);
        cout++;
        printf("Pthread_func01 running is %d s\n",cout);
    }
    // sleep(2);
    return "func01_exit";
}

void *Pthread_func02(void *argv)
{
    int cout=0;
     pthread_t pth_id;
    printf("pth_id-->%lu\n",pthread_self());
    printf("rev-->%s\n",(char *)argv);

     for(int i=0;i<7;i++)
    {
        sleep(2);
        cout++;
        printf("Pthread_func02 running is %d s\n",cout);
    }
    // sleep(2);
    return "func02_exit";
}

/*
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg );--创建线程
*/

int main(void)
{
    pthread_t p_th1,p_th2;
    int ret;

    ret=pthread_create(&p_th1,NULL,Pthread_func01,"p_th1:hello");
    if(ret!=0)
    {
        printf("线程1创建失败\n");
        // exit(-1);
    }
    ret=pthread_create(&p_th2,NULL,Pthread_func02,"p_th2:hello");
    if(ret!=0)
    {
        printf("线程2创建失败\n");
        // exit(-1);
    }

//int pthread_join(pthread_t thread, void **retval);

    char *func_str;
    pthread_join(p_th1,(void *)&func_str);
     printf("p_th1-->%s\n",func_str);

    // pthread_join(p_th2,(void *)&func_str);
    //  printf("p_th2-->%s\n",func_str);
    //int pthread_detach(pthread_t thread);

      pthread_detach(p_th2);
    // while(1);
    // getchar();
    return 0;
}

3.线程的退出及取消

线程的退出:

#include <pthread.h>
void pthread_exit(void *retval);
功能:
退出调用线程。 一个进程中的多个线程是共享该进程的数据段, 因此, 通常线程退出
后所占用的资源并不会释放。
参数:
retval: 存储线程退出状态的指针。
返回值: 无
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <pthread.h>
/*
pthread_t pthread_self(void);--线程ID
*/

void *Pthread_func01(void *argv)
{
    int cout=0;
    pthread_t pth_id;
    printf("pth_id-->%lu\n",pthread_self());
    printf("rev-->%s\n",(char *)argv);
    for(int i=0;i<5;i++)
    {
        sleep(1);
        cout++;
        printf("Pthread_func01 running is %d s\n",cout);
    }
    // sleep(2);
    return "func01_exit";
}

void *Pthread_func02(void *argv)
{
    int cout=0;
     pthread_t pth_id;
    printf("pth_id-->%lu\n",pthread_self());
    printf("rev-->%s\n",(char *)argv);

     while(1)
    {
        sleep(1);
        cout++;
        printf("Pthread_func02 running is %d s\n",cout);
        if(cout==7)
        {
            // void pthread_exit(void *retval);
           pthread_exit("func02_pthread_exit");

        }
    }
    // sleep(2);
    return "func02_exit";
}

/*
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg );--创建线程
*/

int main(void)
{
    pthread_t p_th1,p_th2;
    int ret;

    ret=pthread_create(&p_th1,NULL,Pthread_func01,"p_th1:hello");
    if(ret!=0)
    {
        printf("线程1创建失败\n");
        // exit(-1);
    }
    ret=pthread_create(&p_th2,NULL,Pthread_func02,"p_th2:hello");
    if(ret!=0)
    {
        printf("线程2创建失败\n");
        // exit(-1);
    }

//int pthread_join(pthread_t thread, void **retval);

    char *func_str;
    pthread_join(p_th1,(void *)&func_str);
     printf("p_th1-->%s\n",func_str);

    pthread_join(p_th2,(void *)&func_str);
     printf("p_th2-->%s\n",func_str);
    int pthread_detach(pthread_t thread);
    // while(1);
    // getchar();
    return 0;
}

线程的取消

#include <pthread.h>
int pthread_cancel(pthread_t thread);
功能:
杀死(取消)线程
参数:
thread : 目标线程 ID。
返回值:
成功: 0
失败: 出错编号

设置取消点:
void pthread_testcancel(void);



在 Linux 系统下,线程默认可以被取消。编程时可以通过 pthread_setcancelstate
函数设置线程是否可以被取消。
pthread_setcancelstate(int state,int *old_state);
state:
PTHREAD_CANCEL_DISABLE:不可以被取消
PTHREAD_CANCEL_ENABLE:可以被取消。
old_state:
保存调用线程原来的可取消状态的内存地址。

注意: 线程的取消并不是实时的, 而又一定的延时。 需要等待线程到达某个取消点(检查点)。 类似于玩游戏存档, 必须到达指定的场所(存档点, 如: 客栈、 仓库、 城里等)才能存储进度。

杀死线程也不是立刻就能完成, 必须要到达取消点。取消点: 是线程检查是否被取消, 并按请求进行动作的一个位置。 通常是一些系统调用xxx_ creat, open, pause, close, read, write..... 执行命令 man 7 pthreads 可以查看具备这些取消点的系统调用列表。 可粗略认为一个系统调用(进入内核)即为一个取消点。

线程的取消点(man 7 pthreads)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <pthread.h>
/*
pthread_t pthread_self(void);--线程ID
*/

void *Pthread_func01(void *argv)
{
    int cout=0;
    pthread_t pth_id;
    printf("pth_id-->%lu\n",pthread_self());
    printf("rev-->%s\n",(char *)argv);
    for(int i=0;i<5;i++)
    {
        sleep(1);
        cout++;
        printf("Pthread_func01 running is %d s\n",cout);
    }
    // sleep(2);
    return "func01_exit";
}

void *Pthread_func02(void *argv)
{
    int cout=0;
     pthread_t pth_id;
    printf("pth_id-->%lu\n",pthread_self());
    printf("rev-->%s\n",(char *)argv);
     pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);//关闭取消点
    // pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);//开启取消点


     for(int i=0;i<9;i++)
    {
        sleep(1);
        cout++;
        printf("Pthread_func02 running is %d s\n",cout);
       
    }
    // sleep(2);
    return "func02_exit";
}

/*
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg );--创建线程
*/

int main(void)
{
    pthread_t p_th1,p_th2;
    int ret;

    ret=pthread_create(&p_th1,NULL,Pthread_func01,"p_th1:hello");
    if(ret!=0)
    {
        printf("线程1创建失败\n");
        // exit(-1);
    }
    ret=pthread_create(&p_th2,NULL,Pthread_func02,"p_th2:hello");
    if(ret!=0)
    {
        printf("线程2创建失败\n");
        // exit(-1);
    }

//int pthread_join(pthread_t thread, void **retval);

    char *func_str;
    pthread_join(p_th1,(void *)&func_str);
     printf("p_th1-->%s\n",func_str);


   //int pthread_cancel(pthread_t thread);

    sleep(1);
    pthread_cancel(p_th2);
    pthread_join(p_th2,(void *)&func_str);
    printf("p_th2-->%s\n",func_str);
    // int pthread_detach(pthread_t thread);


    // while(1);
    // getchar();
    return 0;
}

4.线程的属性

线程是属于进程的,但是线程中的线程运行所需的栈空间和程序计数器等都是独立的,因此对于线程的属性也可以进行单独设置

typedef struct
{
    int etachstate; //线程的分离状态
    int schedpolicy; //线程调度策略
    struct sched_param schedparam; //线程的调度参数
    int inheritsched; //线程的继承性
    int scope; //线程的作用域
    size_t guardsize; //线程栈末尾的警戒缓冲区大小
    int stackaddr_set; //线程的栈设置
    void* stackaddr; //线程栈的位置
    size_t stacksize; //线程栈的大小
} pthread_attr_t;

线程属性初始化及销毁

//线程属性初始化
 int pthread_attr_init(pthread_attr_t *attr);
参数:
    attr---线程属性,获取属性的地址
 函数返回值:
 成功:0;失败:错误号

 //线程属性资源销毁
 int pthread_attr_destroy(pthread_attr_t *attr);
 函数返回值:成功:0;失败:错误号

通过属性进行线程分离:

线程分离状态的函数

设置线程属性,分离 or 非分离
 int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);

 获取程属性,分离or 非分离
 int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);

 参数:
 attr:已初始化的线程属性
 detachstate:
 分离状态:
 PTHREAD_CREATE_DETACHED(分离线程)
 PTHREAD_CREATE_JOINABLE(非分离线程)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <pthread.h>
/*
pthread_t pthread_self(void);--线程ID
*/

void *Pthread_func01(void *argv)
{
    int cout=0;
    pthread_t pth_id;
    printf("pth_id-->%lu\n",pthread_self());
    printf("rev-->%s\n",(char *)argv);
    for(int i=0;i<5;i++)
    {
        sleep(1);
        cout++;
        printf("Pthread_func01 running is %d s\n",cout);
    }
    // sleep(2);
    return "func01_exit";
}

void *Pthread_func02(void *argv)
{
    int cout=0;
     pthread_t pth_id;
    printf("pth_id-->%lu\n",pthread_self());
    printf("rev-->%s\n",(char *)argv);
    //  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);//关闭取消点
    // pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);//开启取消点


     for(int i=0;i<9;i++)
    {
        sleep(1);
        cout++;
        printf("Pthread_func02 running is %d s\n",cout);
       
    }
    // sleep(2);
    return "func02_exit";
}

/*
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg );--创建线程
*/

int main(void)
{
    pthread_t p_th1,p_th2;
    int ret;

pthread_attr_t attr;

//初始化线程属性,获取属性的地址
//int pthread_attr_init(pthread_attr_t *attr);
    pthread_attr_init(&attr);

//int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
    ret=pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
    if(ret==0)
    {
        printf("设置属性成功\n");
    }

    ret=pthread_create(&p_th1,NULL,Pthread_func01,"p_th1:hello");
    if(ret!=0)
    {
        printf("线程1创建失败\n");
        // exit(-1);
    }
    ret=pthread_create(&p_th2,&attr,Pthread_func02,"p_th2:hello");
    if(ret!=0)
    {
        printf("线程2创建失败\n");
        // exit(-1);
    }

//int pthread_join(pthread_t thread, void **retval);

    char *func_str;
    pthread_join(p_th1,(void *)&func_str);
     printf("p_th1-->%s\n",func_str);


   //int pthread_cancel(pthread_t thread);

    sleep(1);
    
    pthread_cancel(p_th2);
    pthread_join(p_th2,(void *)&func_str);
    printf("p_th2-->%s\n",func_str);
    // int pthread_detach(pthread_t thread);


    // while(1);
    // getchar();
    return 0;
}

设置线程栈空间:

如果我们对程序的性能提出更高的要求那么需要设置线程属性, 比如可以通过设置线程栈的大小来降低内存的使用, 增加最大线程个数。

//设置栈的地址
 int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
    attr:指向 pthread_attr_t 类型的指针,表示要设置的线程属性。
    stackaddr:指向堆栈的起始地址的指针,可以使用 NULL 表示使用默认的堆栈。
    stacksize:堆栈的大小,以字节为单位。
 成功:0;失败:错误号

 //得到栈的地址
 int pthread_attr_getstack(pthread_attrt *attr, void **stackaddr, sizet*stacksize);
 成功:0;失败:错误号
 参数:
 attr:指向一个线程属性的指针
 stackaddr:返回获取的栈地址
 stacksize:返回获取的栈大小

 //设置线程所使用的栈空间大小
 int pthread_attr_setstacksize(pthread_attr_t *attr, sizet stacksize);
 成功:0;失败:错误号
 //得到线程所使用的栈空间大小
 int pthread_attr_getstacksize(pthread_attr_t*attr, size_t *stacksize);
 成功:0;失败:错误号

 参数:
 attr:指向一个线程属性的指针
 stacksize:返回线程的堆栈大小

栈空间大小的设置问题:

为什么设置大小为100个字节不行,但是17000就可以

单片机中学习flash的时候,学习的存储中的单位:块 扇区 页 页内大小

在我们的Ubuntu中,进程中默认的空间大小8M空间--可以修改

但是系统中每一个页的大小都是16KB--16384字节,每次去修改线程大小的时候,都必须要大于等于一个页,必须大于16KB

这也是导致我们开辟空间的时候,开辟100字节失败的原因

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <pthread.h>
/*
pthread_t pthread_self(void);--线程ID
*/

void *Pthread_func01(void *argv)
{
    int cout=0;
    pthread_t pth_id;
    printf("pth_id-->%lu\n",pthread_self());
    printf("rev-->%s\n",(char *)argv);
    for(int i=0;i<5;i++)
    {
        sleep(1);
        cout++;
        printf("Pthread_func01 running is %d s\n",cout);
    }
    // sleep(2);
    return "func01_exit";
}

void *Pthread_func02(void *argv)
{
    int cout=0;
     pthread_t pth_id;
    printf("pth_id-->%lu\n",pthread_self());
    printf("rev-->%s\n",(char *)argv);
    //  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);//关闭取消点
    // pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);//开启取消点
     for(int i=0;i<9;i++)
    {
        sleep(1);
        cout++;
        printf("Pthread_func02 running is %d s\n",cout);
    }
    // sleep(2);
    return "func02_exit";
}
/*
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg );--创建线程
*/

int main(void)
{
    pthread_t p_th1,p_th2;
    int ret;
    int sta_stacksize;
pthread_attr_t attr;

//初始化线程属性,获取属性的地址
//int pthread_attr_init(pthread_attr_t *attr);
    pthread_attr_init(&attr);

//int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
    ret=pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
    if(ret==0)
    {
        printf("设置属性成功\n");
    }

//设置栈空间大小
//int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);

  void *sta_stack =calloc(1,17000);
  ret=  pthread_attr_setstack(&attr,sta_stack,17000);
   if(ret==0){
    printf("pthread_attr_setstack is ok\n");
    // printf("sta_stacksize-->%d\n"sta_stacksize);
  }

// int pthread_attr_getstack(pthread_attrt *attr, void **stackaddr, sizet*stacksize);
  ret= pthread_attr_getstack(&attr,&sta_stack,(sizet*)&sta_stacksize);
  
  if(ret==0){
    printf("当前堆栈空间设置成功\n");
    printf("sta_stacksize-->%d\n",sta_stacksize);
  }


    ret=pthread_create(&p_th1,NULL,Pthread_func01,"p_th1:hello");
    if(ret!=0)
    {
        printf("线程1创建失败\n");
        // exit(-1);
    }
    ret=pthread_create(&p_th2,&attr,Pthread_func02,"p_th2:hello");
    if(ret!=0)
    {
        printf("线程2创建失败\n");
        // exit(-1);
    }

//int pthread_join(pthread_t thread, void **retval);

    char *func_str;
    pthread_join(p_th1,(void *)&func_str);
     printf("p_th1-->%s\n",func_str);


   //int pthread_cancel(pthread_t thread);

    sleep(1);
    
    pthread_cancel(p_th2);
    pthread_join(p_th2,(void *)&func_str);
    printf("p_th2-->%s\n",func_str);
    // int pthread_detach(pthread_t thread);

    // while(1);
    // getchar();
    return 0;
}

作业:

通过键盘输入创建线程,创建多线程,实现线程的计数(0-20),每一个线程的退出和资源回收;

标签:include,07,--,void,int,线程,pthread,概述,多线程
From: https://blog.csdn.net/weixin_46131184/article/details/136787372

相关文章

  • 协同编辑功能实现原理概述
    协同编辑是一种多用户同时在线编辑同一文档或项目的技术,允许多人实时或异步地对内容进行添加、删除和修改,但是不会互相覆盖各自的修改。这在文档编辑、软件开发等领域非常流行和有用,比如飞书文档、谷歌doc等。协同编辑主要面临的技术问题包括:版本管理、冲突检测、合并冲突、实时......
  • LCR 071. 按权重随机选择
    题目:给定一个正整数数组w,其中w[i]代表下标i的权重(下标从0开始),请写一个函数pickIndex,它可以随机地获取下标i,选取下标i的概率与w[i]成正比。例如,对于w=[1,3],挑选下标0的概率为1/(1+3)=0.25(即,25%),而选取下标1的概率为3/(1+3)=0.75(即,75%)。也......
  • P2163 [SHOI2007] 园丁的烦恼 题解
    题目链接:园丁的烦恼挺经典的题目,转化成二维数点去做这玩意和常规的偏序计数问题有区别:转化为求\(a\lex\leb\\&\&\c\ley\led\)的数量,这种就别想着拆来拆去了,这种权值类带偏序计数类问题,是经典的可差性问题,我们计:\(ans(x,l,r)\)表示\(t\lex,l\ley\ler\)的数......
  • 推荐系统冷启动问题概述
    冷启动问题简介冷启动问题分三类用户冷启动:如何给新用户做个性化推荐的问题物品冷启动:如何将新的物品推荐给可能对他感兴趣的用户系统冷启动:如何在一个新开发的网站上设计个性化推荐服务提供非个性化的推荐利用用户注册提供的年龄性别利用用户注册时提供的年龄,性别等个......
  • lc907 子数组的最小值之和
    给定数组arr[n],求所有子数组中最小值的和,答案对1e9+7取模。1<=n<=30000;1<=arr[i]<=30000考虑每个数作为最小值对应的子数组有多少个,计算对答案的贡献,而子数组的个数可以用单调栈来维护。数组元素可能相同,为了避免重复计数,用半开半闭区间。classSolution{public:ints......
  • Java面试题:假设你正在开发一个Java后端服务,该服务需要处理高并发的用户请求,并且对内存
    Java内存优化、线程安全与并发框架:综合面试题解析Java作为一种广泛使用的编程语言,其内存管理、多线程和并发处理是开发者必须掌握的核心技能。为了全面评估候选人在这些领域的知识水平和实际应用能力,我们设计了一道综合性的面试题。本文将对这道题目进行深入分析,从核心知识......
  • 洛谷P1097 [NOIP2007 提高组] 统计数字
    #先看题目题目描述某次科研调查时得到了n 个自然数,每个数均不超过1.5×109。已知不相同的数不超过 个,现在需要统计这些自然数各自出现的次数,并按照自然数从小到大的顺序输出统计结果。输入格式共n+1 行。第一行是整数n,表示自然数的个数;第 2至n+1 每行一个自......
  • 【转载】Redis -- IO多路复用及redis6的多线程
    都知道redis是通过单线程+io多路复用来避免并发问题的,然后在redis6的时候redis引入了多线程,这里就来详细说说IO多路复用模型以及redis的多线程。Redis的I/O多路复用模型有效的解决单线程的服务端,使用不阻塞方式处理多个client端请求问题。在看I/O多路复用知识之前,我们先来......
  • java集合框架——Collection集合概述
    前言之前学过ArrayList,现在接触到更多集合了。整理下笔记,打好基础,daydayup! 集合体系结构集合分为单列结合和双列结合,Collection代表单列集合,每个元素只包含一个值。Map代表双列集合,每个元素包含两个值。(本篇主要说明Collection集合) Collection集合Collection集合......
  • java集合框架——List集合概述及ArrayList,LinkedList的区别
    前言:List系列集合是Collection集合中两个系列的其中一个,整理下笔记。打好基础,daydayup!需要了解Collection的,可以看这篇java集合框架——Collection集合概述  List系列集合List系列集合的特点为添加的元素有序,可重复,有索引。在继承了Collection方法的基础上,有很多索引......