UNIX 线程

目录

1 并行的概念

2 线程的定义

3 UNIX关于线程的设计与实现

4 线程相关函数

1、pthread_create()

2、pthread_self()

3、pthread_join()

5 线程的退出

6、线程资源的释放和回收

7 线程同步

7.1 互斥量

7.2 信号量

8 信号量控制线程的代码


本文会讲解UNIX下的线程,线程是开发中会经常用到的并行技术,比如你打开QQ,同时开好几个聊天窗口,这就是用线程实现的。

1 并行的概念

执行代码必须需要内存和CPU。内存可分,CPU不可以分。真正意义的代码的并行是不存在的。视觉、听觉等都是需要时间段的。CPU使用CPU时间片机制实现伪并行,把CPU的执行时间分成极小的小片,比如1ms,每个CPU时间片可以拥有CPU的1ms执行时间,执行完毕后让给其他线程执行。多线程可以提升代码的效率,因此应用较广。

2 线程的定义

线程是一种轻量级的代码并行技术,是程序执行流的最小单元,一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。

线程隶属于某个进程,进程内部可以使用多线程,线程的内部也可以使用多线程。线程共享进程的资源,不需要太多的额外资源,每个线程只需要额外建一个栈区即可。同一个进程内部的多进程之间互相独立,又互相影响。

每个进程至少有一个线程,即主线程(main()函数),主线程退出时,所有线程跟着结束。

3 UNIX关于线程的设计与实现

Linux和Unix都在POSIX规范有了定义,主要是一个头文件+一个动态库。头文件是pthread.h,共享库是libpthread.so。所有线程相关的函数/结构/类型基本都是以pthread_开头,编译链接时,需要加-pthread/-lpthread。所有的线程的函数,都不使用errno,错误码直接返回。函数strerror()可以把错误码转换成错误信息。

4 线程相关函数

1、pthread_create()

这个函数产生一个线程,线程随即开始执行。

int pthread_create(pthread_t *id , pthread_attr_t *attr , void*(*fa)(void*) , void* p );

参数解释

id是一个传出参数,用于传出线程的ID,线程ID是线程的唯一标识,它是一个非常大的整数,unsigned long int。

attr是线程的属性,默认给0即可。

fa是一个函数指针,用来传入线程执行的函数,该函数原型为:

void* fd (void *);

p就是参数fd的传入参数,以此来给线程传入参数。

返回:成功返回0,失败需要用strerror()转换错误信息。

2、pthread_self()

这个函数可以获取当前线程的线程id。

#include <pthread.h>

pthread_t pthread_self(void);

 

参数解释

返回:返回当前线程的线程id。

3、pthread_join()

该函数的作用是让一个线程以阻塞的方式等待另外一个线程的结束,同时可以获取线程的返回值。

#include<pthread.h>

int pthread_join(pthread_t thread , void **retval);

 

参数解释

thread是被等待的线程的id,即哪个线程的唯一标识

retval是一个传出参数,用来传出被等待线程的返回值,如果不需要返回值,给0或NULL即可。

返回:成功返回0,失败则返回错误号,用strerror()查看。

5 线程的退出

和进程一样,线程也有自己的退出方式

1、线程执行了return语句。

2、线程使用pthread_exit(void*)退出线程,并把返回值做参数。

3、线程可能被其他线程取消(非正常退出),使用pthread_cancel()可以取消一个线程,前提是这个线程允许你去取消(了解就可以了,用的不多)。

注:exit()和pthread_exit()的区别是,后者是退出线程的,只会结束当前线程,而exit()是退出进行,会结束所有的线程。

 

6、线程资源的释放和回收

1、普通线程的资源回收,不是十分的确定,没有一个强制的机制。

2、pthread_join()进来的进程,资源会在join函数结束后回收。

3、处于分离状态的线程在一结束的同时就回收资源,不考虑其他线程是否有关系。函数pthread_detach()可以设置线程为分离状态。

#include<pthread.h>

int pthread_detach(pthread_t id);

 

参数解释

id是你要设为分离模式的线程的id

返回:成功返回0,失败返回错误号,用函数strerror()查看错误信息。

7 线程同步

多线程之间共享进程的资源,因此有可能出现数据的冲突,在访问共享数据,多线程之间需要协调访问,这种技术叫线程同步。线程同步技术的核心思想就是在访问共享资源时,并行访问改为串行访问。

Unix系统的线程同步技术主要包括:互斥量、信号量、条件变量,本文只涉及前两种。

 

7.1 互斥量

互斥量有固有的用法和步骤:

1、声明一个互斥量

pthread_mutex_t lock;

2、初始化互斥量(宏定义初始化、函数初始化)

可以在声明的同时使用宏初始化,或者在声明以后使用函数来初始化。

pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;

或:

pthread_mutex_init(&lock,0);

3、给访问的共享资源上锁

pthread_mutex_lock(&lock);

4、访问共享资源

5、访问完毕解锁

pthread_mutex_unlock(&lock);

6、如果不再使用互斥量,可以回收资源(即销毁互斥锁)

pthread_mutex_destroy(&lock);

注意:互斥量使用不当将会造成死锁,导致程序崩溃。

7.2 信号量

信号量是一个计数器,用于控制访问共享资源的并行线程总数,在POSIX规范中,信号量也可以用于进程的控制,但Linux并没有实现。信号量的原理和信号量集中信号量的原理是一样的,但就代码实现来说,它们没有任何关系。

信号量定义在semaphore.h中,信号量的使用步骤和互斥量基本类似,但是信号量不是定义在pthread中,信号量使用步骤:

1、声明信号量

sem_t sem;

2、初始化信号量

sem_init(&sem,0,10);

3、信号量计数减一

sem_wait(&sem);

4、访问共享资源

5、访问完毕,信号量计数加一

sem_post(&sem);

6、回收资源

sem_destory(&sem);

函数解释

int sem_init(sem_t* sem,int which,int value);

参数解释

sem是要初始化的信号量的指针

which 代表控制进行还是控制线程(linux没有实现控制进程),0代表控制线程,非0代表控制进程。

value就是信号量的最大值。

8 信号量控制线程的代码

 

#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>
#include<stdlib.h>
#include<time.h>

sem_t sem;

void* task(void*p){
	int i=(int)p;
	printf("第%d个线程申请连接数据库\n",i);
	sem_wait(&sem);
	printf("第%d个线程申请成功\n",i);
	srand(time(0));
	sleep(rand()%10);
	sem_post(&sem);
	printf("第%d个线程释放连接\n",i);
}

int main(){
	sem_init(&sem,0,10);
	pthread_t id;
	int i;
	for(i=0;i<20;i++){
		pthread_create(&id,0,task,(void*)(i+1));
		pthread_detach(id);
	}
	sleep(19);
	sem_destory(&sem);
	return 0;
}

 

发布了33 篇原创文章 · 获赞 47 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_39545674/article/details/87909137
今日推荐