1 .验证怎么向线程中传递参数,使用返回值:
#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;
}