对线程的深入学习(二)
2015-07-30 21:59
357 查看
1 .验证怎么向线程中传递参数,使用返回值:
注意:pthread_join有两个作用:一个是回收线程资源,另一个是等待子线程结束与主线程汇合,如果没有这个函数直接在pthread_create打印的话,由于由于父子执行顺序是不定的,所以我们不一定能得到正确的面积,
2. 终止线程
retval - 和线程过程函数的返回值语义相同。
3 . 取消线程
1) 向指定线程发送取消请求
注意:该函数只是向线程发出取消请求,并不等待线程终止。 缺省情况下,线程在收到取消请求以后,并不会立即终止,而是仍继续运行,直到其达到某个取消点。在取消点处,线程检查其自身是否已被取消了,并做出相应动作。当线程调用一些特定函数时,取消点会出现,对可能引发阻塞的函数会检查取消点。
2) 设置调用线程的可取消状态
state取值:
PTHREAD_CANCEL_ENABLE - 接受取消请求(缺省)。
PTHREAD_CANCEL_DISABLE - 忽略取消请求。
3) 设置调用线程的可取消类型
type取值:
PTHREAD_CANCEL_DEFERRED - 延迟取消(缺省)。
被取消线程在接收到取消请求之后并不立即响应,而是一直等到执行了特定的函数(取消点)之后再响应该请求。
PTHREAD_CANCEL_ASYNCHRONOUS - 异步取消。
被取消线程可以在任意时间取消,不是非得遇到取消点才能被取消。但是操作系统并不能保证这一点。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <unistd.h> #include <pthread.h> #define PAI 3.14159 void* thread_area (void* arg) { //计算面积 double r = *(double*)arg; *(double*)arg = PAI * r * r;//用输出参数把值带回到主函数 return NULL; } int main (void) { printf ("r = "); double rs; scanf ("%lf", &rs);//输入半径 pthread_t tid; int error = pthread_create (&tid, NULL, thread_area, &rs);//注意这时候传的是rs的地址,而不是直接传值 if (error) { fprintf (stderr, "pthread_create: %s\n", strerror (error)); return -1; } if ((error = pthread_join (tid, NULL)) != 0) { fprintf (stderr, "pthread_join: %s\n", strerror (error)); return -1; } printf ("s = %g\n", rs);//这个时候就能保证子线程已经被执行,现在rs里边装的就一定是正确的面积 return 0; }
注意:pthread_join有两个作用:一个是回收线程资源,另一个是等待子线程结束与主线程汇合,如果没有这个函数直接在pthread_create打印的话,由于由于父子执行顺序是不定的,所以我们不一定能得到正确的面积,
//参数arg是结构体的情况 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <unistd.h> #include <pthread.h> #define PAI 3.14159 typedef struct tag_Pyth {//两个直角边,和一个斜边 double a; double b; double c; } PYTH, *LPPYTH; void* thread_pyth (void* arg) { LPPYTH pyth = (LPPYTH)arg; pyth -> c = sqrt (pyth -> a * pyth -> a + pyth -> b * pyth -> b);// a方加b方再开方 return NULL; } int main (void) { int error; pthread_t tid; PYTH pyth;//读入两条边的值 计算另外一条的值 printf ("a = "); scanf ("%lf", &pyth.a); printf ("b = "); scanf ("%lf", &pyth.b); if ( error = pthread_create (&tid, NULL, thread_pyth, &pyth) != 0) { fprintf (stderr, "pthread_create: %s\n", strerror (error)); return -1; } if(error = pthread_join (tid, NULL) != 0) { fprintf (stderr, "pthread_join: %s\n", strerror (error)); return -1; } printf ("c = %g\n", pyth.c); return 0; }
//用返回值的方法把圆的面积带回到主线程 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #define PAI 3.14159 void* thread_area (void* arg) { double r = *(double*)arg; /* double s; s = PAI * r * r; return &s; */ double* s = malloc (sizeof (double)); *s = PAI * r * r; return s; } int main (void) { printf ("r = "); double r; scanf ("%lf", &r); pthread_t tid; int error = pthread_create (&tid, NULL, thread_area, &r); if (error) { fprintf (stderr, "pthread_create: %s\n", strerror (error)); return -1; } double* x; if ((error = pthread_join (tid, (void**)&x)) != 0) { fprintf (stderr, "pthread_join: %s\n", strerror (error)); return -1; } printf ("x = %g\n", *x); free (s); return 0; }注意:thread_area 函数中的s变量不能是局部变量,会导致返回无效,当然我们可以将s定义为static类型,但是如果是静态变量是被各个线程共享的,会导致并发冲突。最后我们采用malloc申请一块堆内存,这里的s是指针,存贮在栈内存中,而每个线程都有自己独立的栈空间,所以这个方案既不会有返回无效问题也不存在并发冲突。这里的*s是堆内存,所以可以在子线程外边free掉。
2. 终止线程
void pthread_exit (void* retval);
retval - 和线程过程函数的返回值语义相同。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #define PAI 3.14159 void* thread_area (void* arg) { double r = *(double*)arg; double* s = malloc (sizeof (double)); // exit (0); *s = PAI * r * r; pthread_exit (s); // <==> return s; *s = 2 * PAI * r;//这两行根本执行不到,所以对s的值不会产生任何影响 return s; } int main (void) { printf ("r = "); double r; scanf ("%lf", &r); pthread_t tid; int error = pthread_create (&tid, NULL, thread_area, &r); if (error) { fprintf (stderr, "pthread_create: %s\n", strerror (error)); return -1; } double* s; if ((error = pthread_join (tid, (void**)&s)) != 0) { fprintf (stderr, "pthread_join: %s\n", strerror (error)); return -1; } printf ("s = %g\n", *s); free (s); return 0; }所以程序的结果还是打印圆的面积而非周长,这里需要慎用exit函数,因为在任何线程中调用exit函数都将终止整个进程。
3 . 取消线程
1) 向指定线程发送取消请求
int pthread_cancel (pthread_t thread);成功返回0,失败返回错误码。
注意:该函数只是向线程发出取消请求,并不等待线程终止。 缺省情况下,线程在收到取消请求以后,并不会立即终止,而是仍继续运行,直到其达到某个取消点。在取消点处,线程检查其自身是否已被取消了,并做出相应动作。当线程调用一些特定函数时,取消点会出现,对可能引发阻塞的函数会检查取消点。
2) 设置调用线程的可取消状态
int pthread_setcancelstate (int state, int* oldstate);成功返回0,并通过oldstate参数输出原可取消状态 (若非NULL),失败返回错误码。
state取值:
PTHREAD_CANCEL_ENABLE - 接受取消请求(缺省)。
PTHREAD_CANCEL_DISABLE - 忽略取消请求。
3) 设置调用线程的可取消类型
int pthread_setcanceltype (int type, int* oldtype);成功返回0,并通过oldtype参数输出原可取消类型 (若非NULL),失败返回错误码。
type取值:
PTHREAD_CANCEL_DEFERRED - 延迟取消(缺省)。
被取消线程在接收到取消请求之后并不立即响应,而是一直等到执行了特定的函数(取消点)之后再响应该请求。
PTHREAD_CANCEL_ASYNCHRONOUS - 异步取消。
被取消线程可以在任意时间取消,不是非得遇到取消点才能被取消。但是操作系统并不能保证这一点。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> void elapse (void) { size_t i; for (i = 0; i < 800000000; ++i); } void* thread_proc (void* arg) { /* int error = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL); //敲回车,不会终止 if (error) { fprintf (stderr, "pthread_setcancelstate: %s\n", strerror (error)); exit (EXIT_FAILURE); } *//* int error = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);//敲回车后直接终止,但不是总能有效 if (error) { fprintf (stderr, "pthread_setcanceltype: %s\n", strerror (error)); exit (EXIT_FAILURE); } */ for (;;) { printf ("线程:子在川上曰,逝者如斯夫。\n"); elapse (); } return NULL; } int main (void) { setbuf (stdout, NULL); printf ("按<回车>取消线程...\n"); pthread_t tid; int error = pthread_create (&tid, NULL, thread_proc, NULL); if (error) { fprintf (stderr, "pthread_create: %s\n", strerror (error)); return -1; } getchar (); //默认的是延迟终止线程 if ((error = pthread_cancel (tid)) != 0) { fprintf (stderr, "pthread_cancel: %s\n", strerror (error)); exit (EXIT_FAILURE); } printf ("已发送取消请求,等待线程终止...\n"); if ((error = pthread_join (tid, NULL)) != 0) { fprintf (stderr, "pthread_join: %s\n", strerror (error)); return -1; } printf ("线程已终止。\n"); return 0; }
相关文章推荐
- dhtmlx-calendar
- sql server 2000 数据库自动备份设置方法
- MyBatis知多少(23)MyBatis结果映射
- 全局结构体
- 2015 多校联赛 ——HDU5302(构造)
- 黑马程序员——Java学习总结:IO常用方法练习
- 新时代 DevOps 需求下,我们该如何保障服务的安全?
- 2015 多校联赛 ——HDU5302(构造)
- HTML 网页游戏 2048
- Tomcat安装与配置图文教程
- Adapter内的onItemClick监听器四个arg参数
- C++延时程序
- Linux 内核 SCSI IO 子系统分析
- 最流行的android组件大全
- #142 (div.2) A. Dragons
- js constructor问题!
- 基于Ios的简单点名器程序
- 实例讲解C++中lambda表达式
- iBatis开发详解(4)-----------select详解
- #Exception#Cpp引入异常的原因、关于异常的吐槽以及何时使用异常