线程(遇到问题随时更新)

因为内核为每个线程都开辟了独立空间(task_struct),所以进程间互不影响,但切换时系统开销太大,所以引入了一个轻量级进程(LWP),也就是线程了。

线程共享地址空间,但因为Linux本事是不区分进程和线程的,所以要通过一系列的命令来达成我们的目的

多线程的好处: 提高任务切换效率;
避免额外TLB&cache刷新;

线程共享资源:可执行的命令、静态数据、进程打开的文件描述符、当前工作目录、用户ID、用户组ID

线程私有资源:线程ID(TID),PC(程序计数器)和相关寄存器、堆栈、错误号、优先级、执行状态和属性

线程库

创建线程
#include <pthread.h>
int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*touyine)(void *),void *arg);
返回值:成功:0,失败:错误码
thread:线程对象
attr:线程属性,NULL为默认属性
routine:线程要执行的函数
arg:传给函数的参数

回收线程
#include <pthread.h>
int pthread_join(pthread_t thread,void **retval);
返回值:成功:0,失败:错误码
thtead:线程回收对象
*retval:用来接收线程thread的返回值
此函数调用线程一直阻塞到thread结束

结束线程
#include <pthread.h>
void pthread_exit(void *retval)
没有返回值;
线程私有资源被释放
retval可以被其他线程通过回收(pthread_jion)获取

示例:

char msg[32] = "hello world";
void *thread_func(void *arg);
int main(void)
{
	pthread_t a_thread;
	void *result;
	if(pthread_create(&a_thread,NULL,thread_func,NULL) != 0)
	{	//以线程对象a_thread创建线程,函数thread_func
		printf("fail create\n");
		exit(-1);
	}
	pthread_join(a_thread,&result);
	//回收线程a_thread,将结果存入地址result
	printf("result is %s\n",result);
	printf("message is %s\n",message);
	return 0;
}
void *thread_func(void *arg)
{
	sleep(1);
	strcpy(msg,"maked by thread");
	pthread_exit("thank you")
}
/*
运行结果:result is thank you 
		message is maked by thread
以上示例具体流程:1.创建线程并执行函数(thread_func)
		2.在函数中在msg中存入字符串,在*retval中存入”thank you“
		3.线程回收,result为线程结束后*retval被pthread_join获取并存入的地址
		4.msg为在函数中存入的字符串
*/

线程的同步与互斥

知道了线程创建,结束,回收的流程后,便要考虑线程间如何进行通信。由于共享地址空间,所以通信很容易,只需要通过全局变量来交换数据便可。但是因为有多个线程访问共享机制往往造成混乱,所以引入了同步或互斥机制

同步便是指多个任务按照先后次序依次配合完成一件事。可是如何排序?这时候在1968年,E.D便引入了信号量的概念,由信号量决定线程继续运行或是阻塞。

互斥是指一次指允许一个任务(进程、线程)访问共享资源,由此引入了临界资源,互斥锁等概念

同步

信号量代表一类资源,根据有没有信号量来决定线程是否运行,就像派工单一样,拿到了才可以干活,干完活了再还回来。
所以具体流程就是:
初始化;
P操作:申请资源;(领牌子)
V操作:释放资源;(还牌子)

int sem_init(sem_t *sem,int pshared,unsigned int value);
返回值:成功:0;失败:EOF
sem:初始化的信号量对象
psharde:线程间:0,进程间:1
信号量初值:有几个牌子。

int sem_wait(sem_t *sem); //申请
返回值:成功:0;失败:EOF
sem:信号量对象

int sem_post(sem_t *sem); //释放
返回值:成功:0;失败:EOF
sem:信号量对象

编译时添加 -lpthread

示例1,读写一个信号量:

char buf[32];	
sem_t sem;	//定义全局变量
void *function(void *arg);
int main(void)
{
	pthread_t a_thread;
	if(sem_init(&sem,0,0) < 0)	//1信号量初始化
	{
		perror("sem_init");
		exit(-1);
	}
	if(pthread_create(&a_thread,NULL,function,NULL) != 0)
	{				//2创建线程并执行函数
		printf("failed create\n");
		exit(-1);
	}
	printf("input 'quit' to exit\n");
	do{
		fgets(buf,32,stdin);	//4键盘输入
		sem_post(&sem);		//5释放资源,还牌子
	}while(strncmp(buf,"quit",4));
}
void *function(void *arg)
{
	while(1)
	{
		sem_wait(&sem);		//3申请资源
		printf("you enter %d characters\n",strlen(buf));
	}
}

示例2,读写两个信号量,框架与上例相同,只是多了信号量:

char buf[32]; 				 //定义全局变量
sem_t sem_r,sem_w;	
//定义读信号量和写信号量,不妨定义为一个红牌子(读),一个绿牌子(写)
void *function(void *arg);
int main(void)
{
	 pthread_t a_thread;
  	if(sem_init(&sem_r,0,0) < 0)	 //读信号量初始化,有1个红牌
	{
		perror("sem_init");
		exit(-1);
	}
	if(sem_init(&sem_w,0,0) < 0) 	//写信号量初始化,有一个绿牌

	 {
			perror("sem_init");
 			exit(-1);
	 }

	if(pthread_create(&a_thread,NULL,function,NULL) != 0)
	{    				//创建线程并执行函数
	printf("failed create\n");
	exit(-1);
	}
	printf("input 'quit' to exit\n");
	do{
		sem_wait(&sem_w);	//给绿牌,开始输入,(刚开始没有就不给了)
		fgets(buf,32,stdin);	//键盘输入
	 	sem_post(&sem_r);  	//还红牌
	}while(strncmp(buf,"quit",4));
	return 0;
}
void *function(void *arg)
{
	while(1)
	{
	sem_wait(&sem_r);		//给红牌,告诉结果
	printf("you enter %d characters\n",strlen(buf));
	sem_post(&sem_w);		//还绿牌,
	}
}

互斥

定义: 临界资源:一次只允许一个任务(进程、线程)访问的共享资源。
临界区:访问临界资源的代码。
互斥机制:访问临界资源前申请锁,访问完后释放锁。

有定义看出,与信号量大致相同。既初始化,申请锁,释放锁。

#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);
返回值:成功:0;失败:错误码
mutex:要初始化的互斥锁对象
attr:互斥锁属性,NULL表示缺省属性

int pthread_mutex_lock(pthread_mutex_t *mutex);
返回值:成功:0;失败:错误码
若无法获得锁,则任务阻塞

int pthread_mutex_unlock(pthread_mutex_t *mutex);
返回值:成功:0;失败:错误码
注意执行完临界区应立即释放锁

示例:

void *function(void *arg);

pthread_mutex_t lock;
unsigned int count,value1,value2;

int main(voiid)
{	
	pthread_t a_thread;
	if(pthread_mutex_init(&lock,NULL) != 0)
	{			//初始化锁
		printf("fail\n");
		exit(-1);
	}
	if(pthread_create(&a_thread,NULL,function,NULL) != 0)
	{			//创建线程
		printf("failed\n");
		exit(-1);
	}

	while(1)		//理论上value1 =value2
	{
		count++;
#ifdef _LOCK_
	  pthread_mutex_lock(&lock);
#endif  
	value1 =count;
	value2 =count;
#ifdef _LOCK_
  	pthread_mutex_lock(&lock);
#endif  

	}
return 0;
}

void *function(void *arg)
{
	while(1)
	{
#ifdef _LOCK_
	pthread_mutex_lock(&lock);
#endif		
	if(value1 != value2)		//当不相等时答应,相等则不打印
	{	
		printf("value1 = %u,value2 =%u\n",value1,value2);
		usleep(100000);	
	}
#ifdef _LOCK_
	pthread_mutex_lock(&lock);
#endif  
	
	}
return NULL;
}

示例程序的结果显示,当不加锁的时候总会有几个时刻value1与value2相差1点,加锁时则永远相等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值