首页 > 编程语言 > 详细

Linux 系统编程 学习:009-线程

时间:2020-03-27 19:15:38      阅读:62      评论:0      收藏:0      [点我收藏+]

Linux 系统编程 学习:009-线程

背景

我们在此之前完成了 有关进程的学习。从这一讲开始我们学习线程。

Linux 系统编程 学习:有关概念中,我们介绍了线程和进程的概念。

概念

我们知道:

  • 线程是cpu或操作系统调度的基本单位。线程大部分的资源是共享的,仅仅申请了自己的栈、空间。
  • 线程是进程内部的一个执行分支,线程量级很小。
  • 在程序中创建线程,可以提高效率,进程内线程越多,争夺到CPU的概率就越大,执行代码的概率就越大(有一个度)。
  • 线程可以解决很多问题,而不会像进程一样有那么多的开销。
  • 在线程中需要注意同步的问题。

线程开发基本步骤

#if 0
为什么要用线程
http://blog.csdn.net/huangyimo/article/details/46756151
	线程比进程更快,开销更小。

	1.当需要在在进程间共享数据时,我们必须使用IPC来进行通信,因为两个进程间没有“天生”的共享内存区(进程要求虚拟空间独立,如果想共享数据,必须把这几个进程的某个地址映射到相同的物理内存上)。IPC的使用将会导致开销上升。

	2.需要创建新进程时,我们使用fork()函数。虽然该函数不会拷贝所有的数据,但是最基本的数据,比如页表,文件描述符表等还是需要创建的。这也会导致开销上升。

	而线程完全不会有上面的问题。两个线程之间的数据共享是很自然的事,因为同一进程的线程都在一个虚拟地址空间,数据的共享就像变量赋值一样(但要注意同步问题)。线程的创建也比进程的创建快,因为它不需要复制和创建很多数据。

	一个线程的bug很可能会引起该进程的崩溃(所有的线程都在同一个虚拟地址空间内,一个线程能很容易的访问到另一个线程的空间)


线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。(调度的最小单位)

http://blog.csdn.net/suool/article/details/38542543
对于内核来说,没有线程和进程的区分(但是对于用户来说,是有区别的)

每个进程在创建的时候都申请了新的内存空间以存储代码段\数据段\BSS段\堆\栈空间,并且这些的空间的初始化值是父进程空间的,父子进程在创建后不能互访资源.

而每个新创建的线程则仅仅申请了自己的栈,空间,与同进程的其他线程共享该进程的其他数据空间包括代码段\数据段\BSS段\堆以及打开的库,mmap映射的文件与共享的空间,使得同进程下的线程共享数据十分的方便,只需借助这些共享区域即可,但也有问题即是同步问题.

线程开发的基本步骤:

	#include <pthread.h>

	1. 声明以及初始化一个线程属性变量,并通过函数设置线程属性
	 (当不需要设置线程属性的时候,可以在后续参数的pattr部分填入NULL)
		pthread_attr_t pattr;		//如果不需要设置线程属性,则可以不使用这2条语句
		pthread_attr_init(&pattr);	//如果不需要设置线程属性,则可以不使用这2条语句

		//通过函数设置线程属性
			pthread_attr_getaffinity_np		pthread_attr_getdetachstate
			pthread_attr_getguardsize		pthread_attr_getinheritsched
			pthread_attr_getschedparam		pthread_attr_getschedpolicy
			pthread_attr_getscope			pthread_attr_getstack
			pthread_attr_getstackaddr		pthread_attr_getstacksize

			pthread_attr_setaffinity_np		pthread_attr_setdetachstate
			pthread_attr_setguardsize		pthread_attr_setinheritsched
			pthread_attr_setschedparam		pthread_attr_setschedpolicy
			pthread_attr_setscope			pthread_attr_setstack
			pthread_attr_setstackaddr		pthread_attr_setstacksize


			其中,用得最多是关于线程的可分离性。
				// 如果一个进程是分离的,则意味着在线程结束以后,将被系统回收(常用在无反馈的线程中)
				//(而不是变成僵尸来等待 pthread_join 函数的回收)

			int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); 
			/*
				设置线程的可分离性到属性结构体,成功返回0,失败返回errorno
				pthread_attr_t  : 用于赋值的属性结构体
				detachstate	 	: 设置可分离性
 					PTHREAD_CREATE_DETACHED  分离的。
       				PTHREAD_CREATE_JOINABLE  不可分离的,可汇接的(默认值)
       					可汇接的线程在结束时,可以使用以下方式返回值给其他线程
       						void pthread_exit(void *retval);


       				“	多线程的进程就好比一条河流中的多条支流,支流的终点,将重新汇聚在一起。

       																			————叔超硕徳

       		*/

			int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate); 
			// 获取线程属性结构体中的可分离性


	2. 以指定的线程属性#attr(不需要设置线程属性时,默认填入NULL)创建一个线程#start_routine,并传入参数#arg,成功时,赋线程ID到#thread中,返回0,失败返回error number
		int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
							void *(*start_routine) (void *), void *arg);

		/*
			pthread_t tid;
			pthread_create(&tid,NULL,(void *)start_routine,NULL);
		*/

	3. 根据情况来决定是否等待线程的返回值,如果需要等待,以下面的方式进行

		int pthread_join(pthread_t thread, void **retval);
		// 阻塞等待一个线程ID为#thread的不可分离线程的结束,将其返回值传入#reval
		// 成功返回0,失败返回error number

			一个线程所使用的内存资源在应用pthread_join调用之前不会被重新分配,所以对于每个线程必须调用一次pthread_join函数(被分离线程除外)。

	4. 可以根据情况提前取消一个线程的执行
		int pthread_cancel(pthread_t thread);


	5. 不再使用某个线程属性结构体时,应该进行销毁 
		pthread_attr_destroy(&pattr);

#endif

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
void *start_routine(void *arg)
{
	int count = 5;

	while(count--)
	{
		sleep(1);
		printf("int child thread arg=%s\n", (char *)arg);
	}

	return "world"; //pthread_exit("world");
}

int main(void)
{
	pthread_t tid;
	char *string = "hello";
	void *retval;

	pthread_attr_t pattr; // 线程属性结构体 使用前应该初始化(pthread_attr_init )

	pthread_attr_init(&pattr);// 结束后应该回收资源解除初始化(pthread_attr_destroy )

	pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED);// 设置线程的可分离性
	
	errno = pthread_create(&tid, &pattr, start_routine, string);  // 创建线程start_routine,为线程传参数string
	if(errno != 0)
	{
		fprintf(stderr, "creat thread failed:%s\n", strerror(errno));
		return -1;
	}

	pthread_attr_destroy(&pattr);

	printf("in parent thread\n");

	pthread_join(tid, &retval); // 等待线程的结束,并取返回值

	printf("retval = %s\n", (char *)retval);

	return 0;
}

Linux 系统编程 学习:009-线程

原文:https://www.cnblogs.com/schips/p/12582755.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!