嵌入式Linux C多任务编程(线程篇1)

1.什么是线程?

        线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的、能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(寄存器和栈),当时它与同属于一个进程的其他的线程共享进程所拥有的全部资源。

2.为什么有了进程还需要线程?

        此时,我们要从进程的几个缺点入手进行思考。

        (1)从资源上来讲:进程的创建需要大量的资源,而线程是一种非常“节俭”的多任务操作方式。

        (2)从切换效率上来讲:因为每个进程相互独立,互不影响的特点,进程与进程之间的资源是不共享的。当频繁进行进程间的切换时,所带来的进程间上下文的切换的资源开销和时间开销是巨大的。而线程就弥补了这一点的不足,因为同一个进程间的多线程它们除了它们独立的寄存器和栈外是共享进程资源的,所以在进行线程切换时,它们所需要的线程间上下文切换的资源开销和时间开销是远远小于进程间切换的。

        (3)从通信机制上来讲:还是同样的问题,因为不同进程间的资源互不共享,而要进行数据的传递只能通过进程间通信的方式进行,这种方式不仅费时,而且及其不方便。而线程则正因为它同一进程下的线程共享数据空间,所以一个线程的数据可以直接为其他线程所用,这不仅快捷,而且方便。

3.进程和线程的区别

        线程事进程的一个执行单位,是进程内调度实体,比进程更小的独立运行的基本单位。(线程也被称为轻量级进程)

        同一个进程的线程共享本进程的地址空间,而进程则是独立的地址空间。

        一旦进程退出,则进程中所有的线程也全部退出。

        一个进程崩溃后,不会对其他的进程产生影响,但是一个线程崩溃后,整个进程也会随之崩溃,所以说多进程比多线程更强壮。

        线程不可能完全替代进程。

        线程拥有的独立的属性:   

                    每个线程都拥有自己独立的线程ID

                    每个线程都有独立的切换形态

                    调度的优先级

                    拥有自己独立的函数栈

                    拥有自己独立的错误号

                    每个线程都有自己独立的信号屏蔽字和未决信号机

                    每个线程有自己独立的tack_struct结构体

4.线程的特点

        线程是不安全、不稳定、不健壮的(全局变量)

        线程切换的开销很低(实质上就是函数的切换)

        线程通信机制简单(全局变量)

5.线程操作

a)线程的创建

        1)函数原型:

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

                第一个参数:线程id(传出参数)

                第二个参数:线程的属性(优先级、信号屏蔽字),一般为NULL

                第三个参数:线程需要执行的函数(函数指针)

                四字格参数:用来给线程函数传参(没有则为NULL)

        2)头文件;

                #include<pthread.h>

        3)返回值:

                成功:返回0

                失败:返回非零错误号

b)线程的退出

 1)被动退出:

                a)函数原型:

                        int pthread_cancel(pthread_t thread);

                        参数:要退出线程的ID

                b)头文件:

                        #include<pthread.h>

                c)返回值:

                        成功:返回0

                失败:返回非零错误号

        2)主动退出:

                a)函数原型:

                        void pthread_exit(void *retval);

                        参数:线程结束时的返回值

                        当返回值较多时,就封装成结构体,并返回结构体变量地址

                b)头文件:

                        #include<pthread.h>

                c)返回值:

                        成功:返回0

                        失败:返回非零错误号

        3)注册线程退出处理函数:

                a)函数原型:

                        void pthread_cleanup_push(void(*routine)(void*),void *arg);

                        (压栈)

                        参数1:将此函数注册为线程退出处理函数

                        参数2:传递给退出处理函数的参数

                        void pthread_cleanup_pop(int execute);

                        (弹栈)

                        参数1:若为!0:弹栈,并调用退出函数

                        若为0:不弹栈,并调用退出函数

                b)头文件:

                         #include<pthread.h>

                c)注意事项:

                        pthread_cleanup_push函数和pthread_cleanup_pop函数必须配对出现,若pthread_cleanup_pop函数调用不上也必须要写,否则编译不过

                d)弹栈退出原则:

                        调用thread_cleanup_pop(!0);,主动弹栈

                        如果线程是被别人调用pthread_cancel取消,也会弹栈

                        如果线程是调用pthread_exit函数退出,也会弹栈

                注:

                        return退出,不会自动弹栈,

                        如需弹栈,调用thread_cleanup_pop(!0);

 c)线程等待

        1)等待线程的目的

                a)保证线程的退出程序:保证一个线程退出并且回收资源后允许下一个进程退出

                b)回收线程退出时的资源情况:保证当前线程退出后,创建的新线程不会复用刚才退出线程的地址空间

                c)获得新线程退出时的结果是否正确的退出:类似僵尸进程的wait,确保不会造成内存泄漏等问题

        2)函数原型

函数原型:
    int pthread_join(pthread_t thread, void **retval);
    参数1:指定要回收次线程的TID
    参数2:次线程函数返回的返回值
头文件:
    #include<pthread.h>
返回值:
    成功:返回0
    失败:返回错误号

        3)线程资源为什么不采用进程退出后一起回收?

        有些程序(进程)一旦运行后将长期运行,不会结束,所以次线程在结束后,必须回收资源,如果不回收,每结束一个次线程就会导致一部分的资源被占用,慢慢积累就会使整个进程资源越来越少,最后导致进程崩溃,所以次线程结束后,必须回收次线程资源。

d)线程的状态

        1)可结合态:

                        这种状态下的线程时能够被其他进程回收资源或者杀死的。

        2)分离态:

                        这种状态下的线程是不能够被其他线程回收或杀死的。

                        它的存储资源在它终止时由系统自动释放

        3)默认情况下,线程被创建成可结合态

        4)如何避免多线程退出导致的内存泄漏?

                每个可结合线程需要显示的调用pthread_join函数回收

                将其变成分离态的线程:

线程分离函数:

        pthread_detach(TID);

        参数1:要分离线程的TID

修改属性:

        pthread_attr_t

        pthread_attr_init

        pthread_attr_setdetachstate

        (THREAD_CREATE_DETACHED)

        pthread_attr_destroy

 关于线程同步与互斥下一篇再更新。

   

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux C++ 程序中,可以使用 signal 函数来注册信号处理函数,实现对信号的处理。具体操作步骤如下: 1. 定义信号处理函数。例如,可以编写一个名为 sig_handler 的函数,用来处理收到的信号。 2. 在程序中使用 signal 函数注册信号处理函数。例如,可以使用以下语句来注册 SIGTERM 信号处理函数: ``` signal(SIGTERM, sig_handler); ``` 这样,当程序收到 SIGTERM 信号时,就会调用 sig_handler 函数来处理信号。 3. 在 sig_handler 函数中实现对信号的处理。例如,在收到 SIGTERM 信号时,可以先进行一些清理操作,然后尝试使用 exit 函数正常退出程序: ``` void sig_handler(int signum) { // 进行一些清理操作... // 尝试正常退出程序 exit(0); } ``` 如果 exit 函数成功退出程序,那么程序就能够正常退出,不需要再进行后续操作。 4. 如果 exit 函数无法成功退出程序,说明可能出现了一些问题,这时候可以再次使用 signal 函数注册 SIGKILL 信号处理函数,并在 sig_handler 函数中使用 kill 函数向当前进程发送 SIGKILL 信号,强制终止程序: ``` void sig_handler(int signum) { // 进行一些清理操作... // 尝试正常退出程序 exit(0); // 如果程序无法正常退出,再使用 SIGKILL 强制终止程序 signal(SIGKILL, SIG_DFL); kill(getpid(), SIGKILL); } ``` 在这个例子中,首先使用 signal 函数注册了 SIGKILL 信号处理函数,然后使用 kill 函数向当前进程发送 SIGKILL 信号,强制终止程序。注意,在调用 kill 函数时,需要使用 getpid 函数获取当前进程的进程号。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值