Linux下多线程的创建、退出以及等待

  主要是想记录一下自己的学习过程,对有关概念的解释使用的是偏向于口头的语言,以及自己目前的理解,有点类似于随笔,逻辑性可能较差,理解上难免有一些错误,希望可以给予指正。如果以后自己有遗忘的知识点也可以方便回顾。最近一段时间主要在学Linux系统编程,今天了解了有关Linux下多线程的一些知识,大概总结一下吧。

进程,线程,并发,并行:

1.进程:正在执行的程序,资源分配的最小单位;

2.线程:又称轻量级进程,是进程中的一个实体,程序执行的最小单位;

ps:通俗的理解,进程是运行在系统里的,用的都是系统分配的资源;而线程是运行在进程里面的,用的都是进程分配的资源

3.并发:一个CPU在多个任务间快速切换,给人造成多个任务同时执行的假象;(我感觉就像高速公路上4车道,一排同时有4个车,但是只有一个驾驶员,所以他在某一瞬间,只能驾驶其中的一辆汽车)

4.并行:多个CPU同时执行多个任务,因为是多个CPU,所以多个任务真的是在同时进行;(同样就像高速公路上4车道,一排同时有四个车,四个驾驶员同时在驾驶车辆)

  现在电脑都是多核的,所以多线程就可以让多个CPU同时执行一个进程,从而提高效率,在多线程编程实践中,线程的个数往往多于CPU的个数,所以一般都称多线程并发编程而不是多线程并行编程。

线程ID号获取、创建、退出、等待

1.获取线程ID
  #include<pthread.h>    pthreard_t pthread_self(void);

  pthread_t其实就是int但是你要用一个变量去接收这个函数的返回值时,他的类型必须是pthread_t 而不能是int。

2.线程创建
  #include<pthread.h>  int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine)(void *),void *arg);

  返回值: 成功:0;失败 :-1

  第一个值为新创建的线程的ID号,因为要回写,所以用了指针,第二值是设置新线程的属性,一般用NULL即可,第三个是一个函数指针,指向线程开始的函数,传一个类型为void *函数名(void *arg)的函数的函数名,第四个就是线程开始函数的参数,如果没有写NULL即可。

3.线程退出
  #include<pthread.h>    void pthread_exit(void *retval);

分为两种情况:
  ①主线程中,写在main函数结束的时候,因为如果主线程执行完了,进程就会立即结束,而如果主线程创建的线程还没有执行结束,就会因为主线程的结束而强制结束,为了避免这种情况,所以调用这个函数,主线程会等待所有线程都结束的时候才会终止;
  ②子线程中(我不知道这种叫法是否准确),会立即结束子线程,并返回void *retval,大多数情况下是没有返回值的,所以如果要返回值,会配合pthread_join()使用;

4.线程等待
  #include<pthread.h>    int pthread_join(pthread_t tid,void **rval);

  返回值: 成功:0;失败 :错误码

  正如上面提到的这个函数一般会配合pthread_exit()使用,用来接收pthread_exit()的返回值,这个函数会让线程处于阻塞的状态,第一个参数是其等待的线程ID,第二个参数是用来接收返回值; (其实我不太理解的一点是,pthread_exit()函数的返回值是void *retval类型,也就是说其使用void *类型来接收这个返回值不就可以了吗?为什么要用二级指针呢?我自己猜测应该是因为pthread_join()这个函数规定的吧,也就是本来void *也是可以的)

下面来总结一下我写程序中遇到的一些问题和需要注意的一些地方:

1.虽然一个进程里面的多个线程可以共用全局变量,或者创建新线程的时候可以直接传递指针,从而省去使用pthread_exit()函数进行返回值的操作,但是这样会导致一些安全的问题,所以不建议这样做;

2.还是就是pthread_exit(void *retval),虽然他的返回值是一个指针,但是不能直接int *p,返回p因为线程结束,空间就会被释放,所以必须用malloc,int *p = (int *)malloc(sizeof(int)),来进行分配空间;

3.第三点是pthread_exit(void *retval)可以直接返回int或者char类型的数据(因为其数据的排列方式是整形排列方式),不用使用malloc来分配空间,具体写法:
子线程:int num = 1314; pthread_exit ( (void *) num);
主线程:int ret; pthread_join( id, &ret);
但是double,struct以及其他类型数据就不可以;

4.如果需要在屏幕上打印出线程的ID号建议使用%u,因为线程ID号一般数值较大,已经超出了%d的范围;

5.编译时要链接第三方类库:gcc -lpthread
  eg:gcc -lpthread test.c

最后附一段代码,方便理解。

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
/*
*	目的:写一个向线程传递结构体,并返回结构体的模版,实现pow()函数
 */

//定义传递参数的结构体
typedef struct info{
	double a;
	int b;
} ARG;

//定义存储返回值的结构体
typedef struct ret{
	double r;
} RET;

//新线程的开始函数
void * love(void *arg);

int main(void)
{
	//定义相关变量
	int i;
	pthread_t pid;
	ARG data = {1.31,4};
	RET *r;
	//创建一个新的线程
	pthread_create(&pid, NULL, love, &data);
	//方便观察到多线程同时执行的效果	
	for(i = 1; i <= 10; ++i)
	{
		printf("process_01: %d\n",i);
		sleep(1);
	}
	//阻塞等待指定线程返回结果
	pthread_join(pid,&r);
	//将创建线程计算的结果打印到屏幕上
	printf("%lf ^ %d = %lf\n",data.a,data.b,r->r);
	//调用一下线程退出函数
	pthread_exit(NULL);

	free(r);
}
/*
 *	描述:新线程开始函数
 *	功能:计算一个数的指定次方并返回结果
*/
void * love(void *arg)
{
	//定义相关变量
	ARG *data = (ARG *)arg;
	RET *p = (RET *)malloc(sizeof(RET));//线程执行结束空间会被释放,所以使用malloc分配空间
	int i;
	double num = 1;
	//打印相关提示,表名两个线程在同时运行
	printf("process_02: start\n");
	//计算出结果
	for(i = 0; i < data->b; ++i)
	{
		num *= data->a;	
	}

	sleep(5);
	//将要返回的值存储在刚才分配的空间中
	p->r = num;

	printf("process_02: end\n");
	//使用线程退出函数返回计算结果
	pthread_exit(p);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值