嵌入式学习记录 2024.5.10(多线程编程1)

目录

一.线程

二.如何创建并运行一个线程:pthread_create 函数

三.线程和进程的区别

四. 线程名词的解释

五. 线程资源回收函数:

六.线程退出函数:pthread_exit

七.线程取消运行函数:pthread_cancel /pthread_testcancel /pthread_setcancelstate /pthread_setcanceltype

八.练习(个人练习)

一.线程

线程的概念:

线程是进程的最小组成单位:一个进程里面,至少有一个线程的存在,称为主线程,main函数运行的就是所谓的主线程

多线程能做什么?

在学习多线程之前,一个进程只能运行一个循环,在学习了多线程之后,一个进程就能同时运行多个循环。想要同时运行n个循环的话,只要让进程里面拥有n个线程即可。

进程也是进程当中最小的代码执行单位,有一个线程,就能同时执行一份代码,有n个线程,就能同时执行n份代码   “进程是资源分配的最小单位,线程是CPU调度的最小单位”

二.如何创建并运行一个线程:pthread_create 函数

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);

功能描述:创建一个线程 参数 thread:pthread_create函数创建出线程之后,会同步的产生一个对应的线程id号,然后将线程id保存到thread指向的内存里面

参数 attr:线程属性的意思,大多数情况下,直接传0,表示使用默认属性

参数 start_routine:pthread_create函数创建出线程线程之后,该线程运行代码就是 start_routine指针指向的函数所运行的代码

参数 arg:其实是传递给 start_routine 函数的参数 返回值:成功返回0,失败返回非0 注意:线程所在的库,在编译的链接阶段不会自动链接,所以需要我们手动的链接,在编译的最后,加上语句 -lpthread

三.线程和进程的区别

1)内存管理有区别

父进程创建子进程之后,子进程完全拷贝父进程的内存空间。也就是说子进程和父进程之间,内存是独立的,互不干涉

主线程创建子线程之后,子线程只会额外的开销8k的内存空间,这8k内存用存放线程属性,内存的起始位置,终止位置,线程 id等等线程相关的数据

所以,子线程的内存空间,和主线程之间是共享的:主线程和子线程之间,想要访问同一个数据的话,最方便的形式就是全局变量

2)进程是资源的获取单位,线程是资源的分配运行单位

3)基于第二点,多进程之间的切换,切换效率要低于多线程之间的切换

无论是多进程还是多线程之间的切换,切换的形式叫做:时间片轮询,上下文切换

4)多进程之间的运行互不影响:父进程结束运行,不影响子进程的运行。同理子进程结束运行,也不影响父进程的运行但是多线程之间,他们的运行不是完全独立:主线程结束运行,所有线程都得结束运行(因为主线程是主函数,主函数结束了,进程就结束了)。其他线程结束运行,互相之间不影响。

四. 线程名词的解释

1 临界数据:能够被多个线程所访问的数据,就是临界数据

2 临界区域:能够被多个线程所执行的代码,我们称为临界区域

3 互斥与同步:

互斥:当一个临界数据,正在被多个线程所访问的时候,线程与线程之间的关系,也应该保持互斥

同一时间,只有1个线程能够访问临界数据,在所有的访问逻辑完成之前,别的线程不应该访问该临界数据

同步:多个线程,可预测的,又先后顺序的,去访问临界数据

五. 线程资源回收函数:

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

功能描述:指定回收thread线程的资源,并使用 retval 这段内存(该内存中保存的是一个void*指针)用来接受线程结束运行时候的运行状态(也就是线程入口函数 start_routine 的返回值) pthread_join 运行模式 和 wait 是一样的:

1:都是阻塞型函数,不回收到资源,不会解除阻塞的

2:都会去接受被回收对象的结束运行时候的状态 pthread_join 和 wait也是一样的问题:主线程在忙于自己的逻辑,执行不到pthread_join,但是线程有成熟的解决访问 ① 主线程自己本身没活干,这个时候直接pthread_join 就行了 ② 如果主线程自己有活干,怎么办?将线程的属性,设置成分离式属性,分离式属性的作用就是:当线程结束运行之后,所有线程的8k资源,自动回收

如何将一个线程设置成分离式线程:pthread_detach

int pthread_detach(pthread_t thread); 功能描述:传入线程id号,将该线程设置成分离式属性

六.线程退出函数:pthread_exit

void pthread_exit(void *retval); 功能描述:结束当前线程,并且将参数retval作为线程入口函数的返回值,向外返回

七.线程取消运行函数:pthread_cancel /pthread_testcancel /pthread_setcancelstate /pthread_setcanceltype

1.)int pthread_cancel(pthread_t thread);

功能描述:取消线程id为thread的线程的运行 该函数和pthread_exit对比,优势在于:pthread_cancel只要能够获取目标线程的id号,能够在进程的任意部分结束该线程的运行。而pthread_exit只能在线程内部,结束自身的运行 注意:pthread_cancel调用之后,只是向目标线程发送取消运行的信号 至于,接收到取消运行信号的线程,默认操作下,是不会立刻取消运行的,而是运行到下一个退出点之后,才会取消运行。至于这个默认的退出点在哪,不一定 但是,我们可以手动的去设置退出点,线程运行到手动设置的退出点后,肯定会退出运行 怎么手动设置退出点:

2.)void pthread_testcancel(void);

功能描述:手动设置线程的退出点 当然,我们也可以将线程设置成调用cancel之后立刻退出

3.)int pthread_setcancelstate(int state, int *oldstate);

功能描述:用来设置线程取消状态,是能够使用cancel函数取消运行,还是不能使用cancel函数取消运行 参数 state,有2个选择 PTHREAD_CANCEL_ENABLE 默认操作:运行使用cancel取消线程的运行 PTHREAD_CANCEL_DISABLE 不允许使用cancel取消线程的运行

4.)int pthread_setcanceltype(int type, int *oldtype);

功能描述:设置线程cancel的退出类型,是立刻退出还是运行到下一个退出点后才退出 参数type:类型,有2个选择 PTHREAD_CANCEL_DEFERRED: 默认设置,线程取消后,运行到下一个退出点才取消 PTHREAD_CANCEL_ASYNCHRONOUS: 现在在被cancel之后,立刻取消运行,但是系统不保证一定会立刻取消 参数oldtype:用来接受原先线程取消类型,传0表示不接受

如何在线程内部获取线程自身的id号 调用函数 pthread_self 即可,通过返回就能获取

八.练习(个人练习)

在一个进程中,创建一个子线程。 主线程负责:向文件中写入数据 子线程负责:从文件中读取数据 要求使用线程的同步逻辑,保证一定在主线程向文件中写入数据成功之后,子线程才开始运行,去读取文件中的数据

#include <myhead.h>
#include <strings.h>
// 在一个进程中,创建一个子线程。
//  主线程负责:向文件中写入数据
//  子线程负责:从文件中读取数据
//  要求使用线程的同步逻辑,
//  保证一定在主线程向文件中写入数据成功之后,
//  子线程才开始运行,去读取文件中的数据
//
int s = 0; // 临界资源·
void waitres(int *t)
{
    while (*t <= 0)
        ; // 如果s小于0则锁
    *t = *t - 1;
}
void signres(int *t)
{
    *t = *t + 1; // 加上资源
}
void *readfile(void *arg)
{
    waitres(&s); // 检查自己能不能读
    int file = open("06text.txt", O_RDONLY);
    if (file == -1)
    {
        perror("openerr");
        return 0;
    }
    char buf[100] = {0};
    int retval = 0;
    while ((retval = read(file, buf, 100)) != 0 && retval != -1)
    {
        printf("%s\n", buf);
        bzero(buf, retval);
    }
    close(file);
}
int main(int argc, const char *argv[])
{
    pthread_t id;
    if (pthread_create(&id, 0, readfile, 0) != 0)
    {
        perror("pthread_create");
        return 1;
    }
    int file = open("06text.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
    char buf[6] = {"hello"};

    if (write(file, buf, 5) > 0)
    {
        signres(&s); // 允许子进程读
    }

    close(file);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值