上午我说了循环创建多个线程,由于进程与线程是如此的相似,进程我们知道要回收,那么线程也自然要回收啦。我们接着看控制原语:

线程与共享

线程间共享全局变量!

牢记】:线程默认共享数据段、代码段等地址空间,常用的是全局变量。而进程不共享全局变量,只能借助mmap。

pthread_exit函数

将单个线程退出

    void pthread_exit(void *retval);    参数:retval表示线程退出状态,通常传NULL

思考:使用exit将指定线程退出,可以吗?                                            【pthrd_exit.c】

    结论:线程中,禁止使用exit函数,会导致进程内所有线程全部退出。

    在不添加sleep控制输出顺序的情况下。pthread_create在循环中,几乎瞬间创建5个线程,但只有第1个线程有机会输出(或者第2个也有,也可能没有,取决于内核调度)如果第3个线程执行了exit,将整个进程退出了,所以全部线程退出了。

    所以,多线程环境中,应尽量少用,或者不使用exit函数,取而代之使用pthread_exit函数,将单个线程退出。任何线程里exit导致进程退出,其他线程未工作结束,主控线程退出时不能return或exit。

另注意,pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。

总结exit、return、pthread_exit各自退出效果。

return:返回到调用者那里去。

pthread_exit():将调用该函数的线程退出

exit: 将进程退出。

pthread_join函数

阻塞等待线程退出,获取线程退出状态        其作用,对应进程中 waitpid() 函数。

    int pthread_join(pthread_t thread, void **retval); 成功:0;失败:错误号

    参数:thread:线程ID (【注意】:不是指针);retval:存储线程结束状态。

    对比记忆:

        进程中:main返回值、exit参数-->int;等待子进程结束 wait 函数参数-->int *

        线程中:线程主函数返回值、pthread_exit-->void *;等待线程结束 pthread_join 函数参数-->void **

参数 retval 非空用法。

调用该函数的线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:

  1. 如果thread线程通过return返回,retval所指向的单元里存放的是thread线程函数的返回值。
  2. 如果thread线程被别的线程调用pthread_cancel异常终止掉,retval所指向的单元里存放的是常数PTHREAD_CANCELED。
  3. 如果thread线程是自己调用pthread_exit终止的,retval所指向的单元存放的是传给pthread_exit的参数。
  4. 如果对thread线程的终止状态不感兴趣,可以传NULL给retval参数。

上面说的很清楚啦,所以回收线程的代码实现也很简单啦:

#include
<stdio.h>

#include
<pthread.h>

#include
<string.h>

#include
<stdlib.h>

typedef
struct {

    int x;

    int y;

    char p[128];

}my_func;

void *func(void*arg)

{

    my_func *mf = (my_func*)malloc(sizeof(my_func));

    int i = (int)arg;

    mf->x = i;

    mf->y = i * i;

    strcpy(mf->p, "my lover is dandan.");

    printf("我是第%d个线程,我的线程ID是%lu\n", i + 1, pthread_self());

    pthread_exit(mf);

}

int main(void)

{

    pthread_t pth[5];

    my_func *mf;//这里是指针啊,是指针啊,不是一个实例啊

    for (int i = 0; i != 5; i++)

    {

        pthread_create((pth + i), NULL, func, (void*)i);

        if (!pthread_join(pth[i], (void**)&mf))

        {

            printf("回收线程成功!线程ID:%lu。\n", pth[i]);

            printf("my_func中的x = %d, y = %d, p = %s。\n\n", mf->x, mf->y, mf->p);

        }

        else

            printf("失败!\n");

    }

    return 0;

}

主要是各种转化要注意,还有的是:my_func *mf;//这里是指针啊,是指针啊,不是一个实例啊         这句话很重要啊,我就说为什么我的mf输出像是没有经过初始化和赋值操作的。还有,不用担心我没有free而造成内存泄漏,pthread_exit函数是把这些考虑好了的。还有我的pthread_exit是传参数进去的,主要是想获取一下线程退出的状态。是不是和wait很类似?

Linux:回收循环创建的多个线程的更多相关文章

  1. ExecutorService常用方法和newFixedThreadPool创建固定大小的线程池

    1.ExecutorService: 是一个接口,继承了Executor: public interface ExecutorService extends Executor { } 2.Execut ...

  2. Linux 循环创建多个线程

    这里说一下相关的基础知识: 线程概念 什么是线程 LWP:light weight process 轻量级的进程,本质仍是进程(在Linux环境下)     进程:独立地址空间,拥有PCB     线 ...

  3. python 计算机发展史,线程Process使用 for循环创建 2种传参方式 jion方法 __main__的解释

    ########################总结################## #一 操作系统的作用: 1:隐藏丑陋复杂的硬件接口,提供良好的抽象接口 2:管理.调度进程,并且将多个进程对硬 ...

  4. 【摘】Linux虚拟地址空间布局以及进程栈和线程栈总结

    在CSDN上看到的一篇文章,讲的还是满好的. 原文地址:Linux虚拟地址空间布局以及进程栈和线程栈总结 一:Linux虚拟地址空间布局 (转自:Linux虚拟地址空间布局) 在多任务操作系统中,每个 ...

  5. 【Linux】为啥查某个进程的线程,查出来的所有线程的pid不一样啊

    楼上说的linux线程和进程是一样的,这个说法是错误的. 看了楼主的问题,感觉楼主是被PID给弄混了,线程进程都会有自己的ID,这个ID就叫做PID,PID是不特指进程ID,线程ID也可以叫做PID. ...

  6. 每次调用fork()函数之后,父线程和创建出的子线程都是从fork()后开始执行

    Linux下多少个"-"将被打印: 1 2 3 4 5 6 7 8 int main(void){   int i;   for(i=0;i<4;i++){   fork() ...

  7. exec族函数详解及循环创建子进程

    前言:之前也知道exec族函数,但没有完全掌握,昨天又重新学习了一遍,基本完全掌握了,还有一些父子进程和循环创建子进程的问题,还要介绍一下环境变量,今天分享一下. 一.环境变量 先介绍下环境的概念和特 ...

  8. Executors创建的4种线程池的使用

    Java通过Executors提供四种线程池,分别为:newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程.newFixe ...

  9. Linux下的进程类别(内核线程、轻量级进程和用户进程)--Linux进程的管理与调度(四)

    本文中出现的,内核线程,轻量级进程,用户进程,用户线程等概念,如果不太熟悉, 可以参见 内核线程.轻量级进程.用户线程三种线程概念解惑(线程≠轻量级进程) Linux进程类别 虽然我们在区分Linux ...

随机推荐

  1. [UE4]在当前角色正前方2米处生成一个Actor

  2. 初始化ha环境下的hadoop的hdfs

    1)启动zookeeper2)启动所有的journalnode[hadoop@datanode1 ~]$ ~/hadoop-2.7.3/sbin/hadoop-daemon.sh start jour ...

  3. 禁用win7更新

    关闭自动更新服务Windows Update 第一种方法 ---------------------------------------------------------------- Win + ...

  4. iproute2 对决 net-tools

    如今很多系统管理员依然通过组合使用诸如ifconfig.route.arp和netstat等命令行工具(统称为net-tools)来配置网络功能,解决网络故障.net-tools起源于BSD的TCP/ ...

  5. Linux查看DNS服务器及设置DNS服务器

    DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串. 一台主机的dn ...

  6. VS2012常用快捷键!

    Shift+Alt+Enter: 切换全屏编辑Ctrl+B,T / Ctrl+K,K: 切换书签开关Ctrl+B,N / Ctrl+K,N: 移动到下一书签Ctrl+B,P: 移动到上一书签Ctrl+ ...

  7. AFNetWorking 上传功能使用及源码分析

    使用方法比较多,这里列举两种: 第一种: // 1. 使用AFHTTPSessionManager的接口 AFHTTPSessionManager *manager = [AFHTTPSessionM ...

  8. Hadoop分布式文件系统HDFS

    HDFS的探究: HDFS HDFS是 Hadoop Distribute File System的缩写,是谷歌GFS分布式文件系统的开源实现,Apache Hadoop的一个子项目,HDFS基于流数 ...

  9. Java - 35 Java 实例

    Java 实例 本章节我们将为大家介绍 Java 常用的实例,通过实例学习我们可以更快的掌握 Java 的应用. Java 环境设置实例 Java 实例 – 如何编译一个Java 文件? Java 实 ...

  10. for循环中进行联网请求数据、for循环中进行异步数据操作,数据排序错乱问题解决;

    for循环中进行联网请求数据,由于网络请求是异步的,第一个网络请求还没有回调,第二次第三次以及后续的网络请求又已经发出去了,有可能后续的网络请求会先回调:这时我们接收到的数据的排序就会错乱:怎么才能让 ...