对线程的深入学习(二)

来源:互联网 发布: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
原创粉丝点击