码迷,mamicode.com
首页 > 编程语言 > 详细

对线程的深入学习(二)

时间:2015-07-30 23:24:39      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:uc

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;
}
技术分享




版权声明:本文为博主原创文章,未经博主允许不得转载。

对线程的深入学习(二)

标签:uc

原文地址:http://blog.csdn.net/meetings/article/details/47154491

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!