Linux线程函数原型是这样的:

  1. void* thread_fun(void* arg)

它的返回值是 空类型指针,入口参数也是 空类型指针。那么线程的 exit code 也应该是 void * 类型的。但是在主线程怎么捕获子线程的 exit code 并使用的呢?

捕获的思路如下:

1. 在主线程中定义一个 void* tret;

2. 使用 pthread_join(tidxx, &tret);

这样就能够捕获到子线程的 exit code。

但是如何使用呢?这就取决于子线程中的 exit code 具体表示的数据类型了,可以是 int, char *, struct xxxStr 等等,然后直接在主线程中使用类型转换到对应的数据类型就行了。

例如:

  1. /****************************************************************
  2. # File Name: thread_cleanup2.c
  3. # Author : lintex9527
  4. # E-Mail : lintex9527@yeah.net
  5. # Created Time: Sat 22 Aug 2015 11:01:59 AM HKT
  6. # Purpose :
  7. # Outline :
  8. # Usage :
  9. # --------------------------------------------------
  10. # Result :
  11. # --------------------------------------------------
  12. *****************************************************************/
  13.  
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <pthread.h>
  17.  
  18. void* thr_fn01(void *arg)
  19. {
  20. printf("thread 1 start:\n");
  21. pthread_exit((void *));
  22. pthread_exit((void *)"SOT-26"); // the first pthread_exit() works, the rest below that does not execute.
  23. }
  24.  
  25. void* thr_fn02(void *arg)
  26. {
  27. printf("thread 2 start:\n");
  28. pthread_exit((void *)"SOT-363");
  29. }
  30.  
  31. int main(void)
  32. {
  33. int err;
  34. pthread_t tid1, tid2;
  35. void *tret;
  36.  
  37. pthread_create(&tid1, NULL, thr_fn01, (void *));
  38. pthread_join(tid1, &tret);
  39. printf("thread 1 exit code: %d\n", (tret));
  40. printf("thread 1 exit code: %d\n", (int *)(tret));
  41.  
  42. pthread_create(&tid2, NULL, thr_fn02, (void *));
  43. pthread_join(tid2, &tret);
  44. printf("thread 2 exit code: %s\n", (tret));
  45. printf("thread 2 exit code: %s\n", (char *)(tret));
  46.  
  47. return ;
  48. }

执行的结果如下:

  1. $ ./thread_cleanup2.exe
  2. thread start:
  3. thread exit code:
  4. thread exit code:
  5. thread start:
  6. thread exit code: SOT-
  7. thread exit code: SOT-

可以看到“直接使用指针方式” 和 “强制类型转换方式” 输出的结果都一样。

上面的都是基本数据类型方式,那么再试一下其他的数据类型,例如结构体:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <pthread.h>
  5.  
  6. struct personStr{
  7. char name[];
  8. unsigned int age;
  9. char sex; // 'M', 'W'
  10. char ID[];
  11. };
  12.  
  13. void printPerson(const char * str, struct personStr *p)
  14. {
  15. printf("%s\n", str);
  16. printf(" name:%s\n", p->name);
  17. printf(" age: %d\n", p->age);
  18. printf(" sex: %c\n", p->sex);
  19. printf(" ID: %s\n", p->ID);
  20. }
  21.  
  22. struct personStr thisman;
  23.  
  24. void* thr_fn01(void *arg)
  25. {
  26. printf("thread 1 start:\n");
  27. memcpy(thisman.name, "Lee", strlen("Lee"));
  28. thisman.age = ;
  29. thisman.sex = 'M';
  30. memcpy(thisman.ID, "421127xxxx78455623", strlen("421127xxxx78455623"));
  31. printPerson("In pthread 1:", &thisman);
  32.  
  33. pthread_exit((void *)&thisman);
  34. }
  35.  
  36. void* thr_fn02(void *arg)
  37. {
  38. printf("thread 2 start:\n");
  39. pthread_exit((void *)"SOT-363");
  40.  
  41. }
  42.  
  43. int main(void)
  44. {
  45. int err;
  46. pthread_t tid1, tid2;
  47. void *tret;
  48.  
  49. err = pthread_create(&tid1, NULL, thr_fn01, (void *));
  50. pthread_join(tid1, &tret);
  51. printPerson("In main thread:", tret);    // 直接使用指针
  52. printPerson("In main thread:", (struct personStr *)tret);  // 强制类型转换为结构体指针
  53.  
  54. err = pthread_create(&tid2, NULL, thr_fn02, (void *));
  55. pthread_join(tid2, &tret);
  56. printf("thread 2 exit code: %s\n", (tret));
  57. printf("thread 2 exit code: %s\n", (char *)(tret));
  58.  
  59. return ;
  60. }

执行结果如下:

  1. $ ./thread_cleanup2.exe
  2. thread start:
  3. In pthread :
  4. name:Lee
  5. age:
  6. sex: M
  7. ID: 421127xxxx78455623
  8. In main thread:
  9. name:Lee
  10. age:
  11. sex: M
  12. ID: 421127xxxx78455623
  13. In main thread:
  14. name:Lee
  15. age:
  16. sex: M
  17. ID: 421127xxxx78455623
  18. thread start:
  19. thread exit code: SOT-
  20. thread exit code: SOT-

可以看到 “直接使用指针” 和 “强制类型转换”结果都是一样的。如果图方便就直接使用指针,而且这样的代码通用性也好,万一将来某天结构体名字变动了,就需要改动很多地方了,但是也有弊病,就是代码的易读性不好。

有一点奇怪的就是第一个例子中,为什么返回的是整数 int 类型的"100",却能通过指针打印出"100"呢?

这样验证:

  1. printf("thread 1 exit code: %d\nsizeof tret is %d Bytes\nsizeof(int) is %d Bytes.\n", (tret), sizeof(tret), sizeof(int));

结果是这样的:

  1. thread exit code:
  2. sizeof tret is Bytes
  3. sizeof(int) is Bytes.

那么就说明 tret 的确是指针类型的,占用了8个字节的数据,而 int 类型的数据只占用了4个字节,而且进行如下的尝试,编译失败了:

  1. printf("tret * 3 = %d\n", tret * );
  2. 很不幸,失败了,结果:
  3. thread_cleanup2.c:: error: invalid operands to binary * (have void *’ and int’)
  4. make: *** [thread_cleanup2.o] Error

如果的确是想使用 tret 的值100, 可否通过指针取值运算呢?

  1. printf("tret * 3 = %d\n", (*((int *)tret)) * );
  2.  
  3. 很不幸,这样也失败了。

如果要想把返回值 tret 参与其他的运算,就必须使用一个转换的桥梁。利用 “中间变量 = tret”,然后使用这个中间变量,虽然编译会有 warning 提醒,但是的确能使用:

  1. //printf("tret * 3 = %d\n", (*((int *)tret)) * 3);// failed.
  2. //int num = *((int *)tret); // failed.
  3. int num = tret;
  4. printf("num = %d, num * 3 = %d\n", num, num * );
  5.  
  6. 编译提示:
    thread_cleanup2.c:95: warning: initialization makes integer from pointer without a cast
    cc -o thread_cleanup2.exe thread_cleanup2.o -lpthread
  7.  
  8. 运行结果:
    thread 1 exit code: 100
    sizeof tret is 8 Bytes
    sizeof(int) is 4 Bytes.
    num = 100, num * 3 = 30

2015-08-22 13:17:12 于公司。

Linux 下子线程 exit code 在主线程中的使用的更多相关文章

  1. 开子线程下载图片,回到主线程刷新UI步骤

    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [NSThread detachN ...

  2. 用Handler的post()方法来传递线程中的代码段到主线程中执行

    自定义的线程中是不能更新UI的,但是如果遇到更新UI的事情,我们可以用handler的post()方法来将更新UI的方法体,直接传送到主线程中,这样就能直接更新UI了.Handler的post()方法 ...

  3. android4.0以上访问网络不能在主线程中进行以及在线程中操作UI的解决方法

    MONO 调用一个线程操作UI 然后报Only the original thread that created a view hierarchy can touch its views.错误 goo ...

  4. Android中,子线程使用主线程中的组件出现问题的解决方法

    Android中,主线程中的组件,不能被子线程调用,否则就会出现异常. 这里所使用的方法就是利用Handler类中的Callback(),接受线程中的Message类发来的消息,然后把所要在线程中执行 ...

  5. Java线程和多线程(四)——主线程中的异常

    作为Java的开发者,在运行程序的时候会碰到主线程抛异常的情况.如果开发者使用Java的IDE比如Eclipse或者Intellij IDEA的话,可能是不需要直接面对这个问提的,因为IDE会处理运行 ...

  6. [原]unity中WWW isDone方法只能在主线程中调用

    项目中要使用动态加载,原计划是生成WWW对象后,放到一个容器里.由一个独立线程轮询容器里的对象,如果www.isDone为true时,回调一个接口把结果交给请求方. new Thread( new T ...

  7. 主线程中也不绝对安全的 UI 操作

    从最初开始学习 iOS 的时候,我们就被告知 UI 操作一定要放在主线程进行.这是因为 UIKit 的方法不是线程安全的,保证线程安全需要极大的开销.那么问题来了,在主线程中进行 UI 操作一定是安全 ...

  8. 在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)

    下面的代码我调试了将近一个星期,你能够看出什么地方出了问题吗?线程函数: DWORD WINAPI ThreadProc(    while(!bTerminate)    {        // 从 ...

  9. httpUrlConnection连接网络的用法(用到了handle传递消息,在主线程中更新UI)

    由于httpclient在Android5.0以后已经过时,所以官方推荐使用httpUrlConnection来连接网络,现将该连接的基本方法展示,如下 注意:记得加入<uses-permiss ...

随机推荐

  1. ASP.NET MVC使用动态产生meta

    在ASP.NET中,我们是很容易动态为header节点添加meta信息.<动态修改网页Header属性,Title,Meta标签等>http://www.cnblogs.com/insus ...

  2. C#中Guid类型值如何判断不是初始值!

    示例: public Guid _CurrentApplayInfoID { get; set; } 如何判断不是初始值"00000000-0000-0000-0000-0000000000 ...

  3. Python入门笔记(13):列表解析

    一.列表解析 列表解析来自函数式编程语言(haskell),语法如下: [expr for iter_var in iterable] [expr for iter_var in iterable i ...

  4. asp.net 网页抓取内容

    网页抓取代码 using System; using System.Collections.Generic; using System.Linq; using System.Web; // using ...

  5. WebApi传参总动员(三)

    上篇介绍了如何从输入流中获取实体对象.本篇介绍以url形式传递参数.简单的参数不再赘述,这里主要实现形如(string name,Woman woman)这样的参数传递. 本篇及后面几章均涉及js调用 ...

  6. 老外还是喜欢Ubuntu的

    有图为证? 开效果应该是Ubuntu的界面了,当然,不知是不是backtrack. 这里面的Hacker用的电脑都不是水果.是没有给钱么.

  7. If you insist running as root, then set the environment variable RUN_AS_USER=root...

    版权声明:本文为博主原创文章,不经博主允许注明链接即可转载. If you insist running as root, then set theenvironment variable RUN_A ...

  8. mysql root强密码的必要性max_allowed_packet被改成1024引起的风险

    前两天运维反馈说,有些机器的max_allowed_packet隔两天就会被改成1024,导致客户端调用时出错,网上有说内存不够的,也有人工修改的. 运维小姑娘一口咬定肯定没有改过的,而且my.cnf ...

  9. asp.net mvc Html.BeginForm()方法

    Html.BeginForm()方法将会输出<form>标签,而且必须以using包起来,如此便可在using程序代码最后退出时,让asp.net mvc帮你补上<form>标 ...

  10. Vue表单

    gitHub地址: https://github.com/lily1010/vue_learn/tree/master/lesson11 一 vue表单 实在是太简单了,直接来个例子 <!DOC ...