Chinaunix首页 | 论坛 | 博客
  • 博客访问: 373925
  • 博文数量: 48
  • 博客积分: 1032
  • 博客等级: 上士
  • 技术积分: 1256
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-19 13:24
文章分类

全部博文(48)

文章存档

2014年(3)

2013年(23)

2012年(22)

分类: LINUX

2012-10-24 08:54:14

    在进程模型建立很久之后,线程模型才被引入到UNIX系统之中,线程在上世纪60年代被提出,80年代才被广泛使用起来。
    进程的所有信息对该进程的所有线程都是共享的,包括可执行的程序文本、程序全局内存和堆内存、栈以及文件描述符。因此该进程的所有线程能够访问同一存储区。与进程相同,线程也具有ID标识。但是线程ID只在它所属的进程内起作用。一个进程中的线程ID在另一个进程中无意义。当在一个进程中对多个线程进行操作时,线程ID引用相应的线程。
线程标识:
进程ID用pid_t数据类型表示,是一个非负数。线程ID则用pthread_t数据类型来表示(linux中用无符号长整形表示)。

线程比较:

点击(此处)折叠或打开

  1. #include <pthread.h>
  2. int pthread_equal(pthread_t tid1,pthread_t tid2);
  3. 返回值:相等则返回非0值,否则返回0;
获取线程的ID号:

点击(此处)折叠或打开

  1. #include <pthread.h>
  2. pthread_t pthread_self(void);
  3. 返回值:调用线程的ID
创建线程:

点击(此处)折叠或打开

  1. #include <pthread.h>

  2. int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *),void *restrict arg);
  3. 返回值:若成功则返回0,否则返回错误编号;
参数说明:
tidp:当pthread_create成功返回时,由tidp指向内存单元被设置为新创建线程的线程ID;
attr:用于定制各种不同的线程属性,一般为NULL;
start_rtn:表示该线程执行的函数,也就是新创建的线程从start_rtn函数的地址开始运行。该函数只有一个无类型指针参数arg(不是无类型的指针需要强制转换为无类型指针)。
arg:为线程执行函数start_rtn所需的函数。如果start_rtn函数传递的参数不止一个,那么需要将这些参数放到一个结构中,然后把这个结构的地址作为arg参数传入。

例子:由于pthread不是系统默认库,故在编译的时候需要加上-lpthread参数;

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <pthread.h>

  3. void *myThread1(void)
  4. {
  5.     int i;
  6.     for (i=0; i<3; i++)
  7.     {
  8.         printf("This is the 1st pthread,created by zieckey.\n");
  9.         sleep(1);//Let this thread to sleep 1 second,and then continue to run
  10.     }
  11. }

  12. void *myThread2(void)
  13. {
  14.     int i;
  15.     for (i=0; i<3; i++)
  16.     {
  17.         printf("This is the 2st pthread,created by zieckey.\n");
  18.         sleep(1);
  19.     }
  20. }

  21. int main()
  22. {
  23.     int i=0, ret=0;
  24.     pthread_t id1,id2;
  25.     
  26.     /*创建线程1*/
  27.     ret = pthread_create(&id1, NULL, (void*)myThread1, NULL);
  28.     if (ret)
  29.     {
  30.         printf("Create pthread error!\n");
  31.         return 1;
  32.     }
  33.     
  34.     /*创建线程2*/
  35.     ret = pthread_create(&id2, NULL, (void*)myThread2, NULL);
  36.     if (ret)
  37.     {
  38.         printf("Create pthread error!\n");
  39.         return 1;
  40.     }
  41.     
  42.     pthread_join(id1, NULL);
  43.     pthread_join(id2, NULL);
  44.     
  45.     return 0;
  46. }
创建好了线程,但是线程和进程谁先运行呢?答案是进程先运行,在后面的例子中有讲解。从上面例子也可以看成,进程在创建了线程之后有个函数pthread_join()就是等待两个线程运行完毕,如果没有则进程会直接退出,造成线程不能运行。

线程终止
进程中的任意一线程调用了exit、_Exit或者_exit,那么整个进程就会终止。
单个线程可以通过以下三种方式退出,在不终止整个进程的情况下停止它的控制流。
(1)线程只是从启动例程中返回,返回值是线程的退出码。
(2)线程可以被同一进程中的其他线程取消。
(3)线程调用pthread_exit.

点击(此处)折叠或打开

  1. #include <pthread.h>

  2. void pthread_exit(void *rval_ptr);
rval_ptr是一个无类型指针,与传递启动例程的单个参数类似。一般为NULL;其他线程调用pthread_jion函数可以访问到该指针。

点击(此处)折叠或打开

  1. #include <pthread.h>

  2. int pthread_join(pthread_t thread, void **rval_ptr);
  3. 返回值:成功返回0,否则返回错误编号。
调用线程将一直阻塞,知道指定的线程调用pthread_exit、从启动例程中返回或者被取消。
线程可以通过调用pthread_cancel函数来请求取消同一进程中的其他线程

点击(此处)折叠或打开

  1. #include <pthread.h>

  2. int pthread_cancel(pthread_t tid);
  3. 返回值:成功返回0,否则返回错误;
线程可以安排它退出时需要调用的函数,这样的函数称为线程清理处理程序,线程可以建立多个清理处理程序。将创建线程的例子改一下,就可以测试这个函数,让线程2取消线程1的操作。

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <pthread.h>

  3. void *myThread1(void)
  4. {
  5.     int i;
  6.     for (i=0; i<3; i++)
  7.     {
  8.         printf("This is the 1st pthread,created by zieckey.\n");
  9.         sleep(1);//Let this thread to sleep 1 second,and then continue to run
  10.     }
  11. }

  12. void *myThread2(void *tid)
  13. {
  14.     int i,rc;
  15.     printf("tid = %lu\n",tid);
  16.     rc = pthread_cancel((int )tid);
  17.     if (rc == 0)
  18.     {
  19.     printf("cancel success!\n");
  20.     }
  21.     for (i=0; i<3; i++)
  22.     {
  23.         printf("This is the 2st pthread,created by zieckey.\n");
  24.         sleep(1);
  25.     }
  26. }

  27. int main()
  28. {
  29.     int i=0, ret=0;
  30.     pthread_t id1,id2;
  31.     
  32.     /*创建线程1*/
  33.     ret = pthread_create(&id1, NULL, (void*)myThread1, NULL);
  34.     if (ret)
  35.     {
  36.         printf("Create pthread error!\n");
  37.         return 1;
  38.     }
  39.     else
  40.     printf("id1 = %lu\n",id1);
  41.     /*创建线程2*/
  42.     ret = pthread_create(&id2, NULL, (void*)myThread2, (void *)(id1));
  43.     if (ret)
  44.     {
  45.         printf("Create pthread error!\n");
  46.         return 1;
  47.     }
  48.     
  49.     pthread_join(id1, NULL);
  50.     pthread_join(id2, NULL);
  51.     
  52.     return 0;
  53. }
这样线程1中的内容就不会被打印出来。

点击(此处)折叠或打开

  1. #include <pthread.h>

  2. void pthread_cleanup_push(void(*rtn)(void *),void *arg);
  3. void pthread_cleanup_pop(int execute);
这是一组进栈出栈的操作,当线程执行以下动作时调用清理函数,调用参数arg,清理函数rtn的调用顺序是由pthread_cleanup_push函数来安排的。
(1)调用pthread_exit时
(2)响应取消请求时
(3)用非零execute参数调用pthread_clean_pop时。
如果参数execute设置为0,清理函数将不被调用。无论哪种情况,pthread_cleanup_pop都将删除上一次pthread_cleanup_push调用建立的清理处理程序。

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <pthread.h>
  3. #include <unistd.h>
  4. void *clean(void *arg)
  5. {
  6.     printf("cleanup :%s \n",(char *)arg);
  7.     return (void *)0;
  8. }
  9. void *thr_fn1(void *arg)
  10. {
  11.     printf("thread 1 start \n");
  12.     pthread_cleanup_push( (void*)clean,"thread 1 first handler");
  13.     pthread_cleanup_push( (void*)clean,"thread 1 second hadler");
  14.     printf("thread 1 push complete \n");
  15.     if(arg)
  16.     {
  17.         return((void *)1);
  18.     }
  19.     pthread_cleanup_pop(0);
  20.     pthread_cleanup_pop(0);
  21.     return (void *)1;
  22. }
  23. void *thr_fn2(void *arg)
  24. {
  25.     printf("thread 2 start \n");
  26.     pthread_cleanup_push( (void*)clean,"thread 2 first handler");
  27.     pthread_cleanup_push( (void*)clean,"thread 2 second handler");
  28.     printf("thread 2 push complete \n");
  29.     if(arg)
  30.     {
  31.         pthread_exit((void *)2);
  32.     }
  33.     pthread_cleanup_pop(0);
  34.     pthread_cleanup_pop(0);
  35.     pthread_exit((void *)2);
  36. }
  37. int main(void)
  38. {
  39.     int err;
  40.     pthread_t tid1,tid2;
  41.     void *tret;

  42.     err=pthread_create(&tid1,NULL,thr_fn1,(void *)1);
  43.     if(err!=0)
  44.     {
  45.         printf("error .... \n");
  46.         return -1;
  47.     }
  48.     err=pthread_create(&tid2,NULL,thr_fn2,(void *)1);

  49.     if(err!=0)
  50.     {
  51.         printf("error .... \n");
  52.         return -1;
  53.     }
  54.     err=pthread_join(tid1,&tret);
  55.     if(err!=0)
  56.     {
  57.         printf("error .... \n");
  58.         return -1;
  59.     }
  60.     printf("thread 1 exit code %d \n",(int)tret);

  61.     err=pthread_join(tid2,&tret);
  62.     if(err!=0)
  63.     {
  64.         printf("error .... ");
  65.         return -1;
  66.     }

  67.     printf("thread 2 exit code %d \n",(int)tret);
  68.     
  69.     return 1;
  70. }
进程和线程原语的比较:
进程原语                     线程原语                描述
fork                       pthread_create            创建新的控制流
exit                       pthread_exit              从现有的控制流中退出
waitpid                    pthread_join              从控制流中得到退出状态
atexit                     pthread_cleanup_push      注册在退出控制流时调用的函数
getpid                     pthread_self              获取控制流的ID
abort                      pthread_cancel            请求控制流的非正常退出


上面例子程序参考国嵌培训资料。



















阅读(1357) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~