对线程的深入学习(二)
来源:互联网 发布:matlab矩阵运算 编辑:程序博客网 时间:2024/05/22 17:46
1 .验证怎么向线程中传递参数,使用返回值:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <math.h>#include <unistd.h>#include <pthread.h>#define PAI 3.14159void* 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.14159typedef 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.14159void* 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.14159void* 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;}
0 0
- 对线程的深入学习(二)
- 对线程的深入学习(一)
- 对线程的深入学习(三)
- 深入Java线程管理(二):线程的生命周期
- 深入学习JDK 线程池(之二)
- 代理模式深入学习(二)——实现动态代理对事务的封装
- Cuda学习笔记(二)——Cuda中对线程块的设置
- 深入理解操作系统的管程,进程,线程(二)
- java线程池的深入了解(二)
- 对cookie的深入学习
- java对线程(二)
- 深入Phtread(二):线程的同步-Mutex
- 深入Phtread(二):线程的同步-Mutex
- 深入Phtread(二):线程的同步-Mutex
- 深入Phtread(二):线程的同步-Mutex
- 深入Phtread(二):线程的同步-Mutex
- 线程学习(二)
- 线程学习(二)
- ASP.NET MVC - html.beginForm在javascript中获取form信息
- HorizontalDragLayout-模仿QQ客户端的Item滑动删除
- Hadoop中HDFS写入文件的原理剖析
- 算法竞赛入门经典(刘汝佳)1
- Android中Handler的简单应用(一)
- 对线程的深入学习(二)
- Codeforces Round #313 (Div. 2) Problem E - Gerald and Giant Chess
- 如何使能一个RF card
- Aircrack-ng支持网卡列表(上)
- hdu 4283 You are the one 区间dp
- UIButton 传递参数
- VS2013 编译libevent 并且使用!
- sort和qsort的用法
- Android studio build.gradle配置,debug下使用正式签名,重命名apk