Linux 线程

一、基础概念

1.线程:一个程序执行的多个执行路线称为线程。轻量级别的进程,程序执行的最小单元;
2.特点:多个线程共享一个进程的地址空间;

二、线程创建使用相关函数

1.int pthread_create(pthread_t * thread,const pthread_attr_t *attr,void *(*start_routine)(void *),void *arg);

//返回值:成功返回0 ,失败返回错误码,不一定置errno;
//参数:
//thread  获得线程ID
//attr    线程的属性(分离属性和结合属性),通常为NULL表示使用默认属性(结合属性)
//start_routine  线程的执行函数,采用回调方式执行线程函数
//arg   给线程函数传递的参数

//练习:主线程与子线程多数据交换,以及主线程改变子线程的数据

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
struct data1
{
	int int_data;
	short short_data;
	char char_data;
};

int global=0;

void *func1(void *arg1)
{
	struct data1 getData=*(struct data1 *)arg1;
	while(1)
	{
		sleep(1);
		printf("int_data:%d  short_data :%d  char_data :%d\n",getData.int_data,getData.short_data,getData.char_data);
		global++;
	}
}
void *func2(void *arg2)
{
	int *gDtata=(int *)arg2;
	while(1)
	{
		sleep(1);
		printf("global:%d   data:%d\n",global,*gDtata);
		(*gDtata)++;
	}
}
int main(int argc, const char *argv[])
{
	pthread_t tid,tid1;
	int ret;
	int data=10;
	struct data1 past_data={20,40,60};
	ret=pthread_create(&tid,NULL,func1,&past_data);
	if(ret!=0)
	{
		perror("Fail to pthread_create");
		return -1;
	}
	ret=pthread_create(&tid1,NULL,func2,&data);
	if(ret!=0)
	{
		perror("Fail to pthread_create");
		return -1;
	}
	while(1)
	{
		printf("main running:%d\n",data);
		sleep(1);
	}
	return 0;
}

2.线程终止
void pthread_exit(void *retval);//
//结束当前线程的执行
//参数:
/retval //给等待的线程带一个地址值,如果无则填NULL;
(1)如果在主线程中调用了return 或者exit()函数,则进程结束,所有线程均结束;
(2)如果主线程调用了pthread_exit()函数,则仅仅是主线程消亡,主线程等所有子线程结束时才会结束。
//示例:主线程程中return 前调用pthread_exit()函数,等子线程结束,主进程才结束

#include<stdio.h>
#include<pthread.h>
void *func(void *arg)
{
	int data=*(int *)arg;
	while(1)
	{
		sleep(1);
		if(data==4)
		{
			break;
		}
		printf("thread 1  value:%d\n",data++);
	}
	pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
	int ret;
	int value=0;
	pthread_t tid;
	ret =pthread_create(&tid,NULL,func,&value);
	if(ret!=0)
	{
		perror("Fail to pthread_create");
		return -1;
	}
	pthread_exit(NULL);
	return 0;
}

3.等待线程退出函数
(1)int pthread_join(pthread_t thread,void ** pval);//阻塞的方式等待线程结束
//通过pthread_exit(&value);传回线程内部指针,可以带回返回值给二级指针pval,但是,如果传回的是普通变量的值,则在该线程结束后局部变量被回收,值就没有了,可以把传回值value 设置成static 静态变量。
//示例:

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
void *func(void *arg)
{

	int data=*(int *)arg;
	static int value=30;

	while(1)
	{
		sleep(1);
		if(data==4)
		{
			break;
		}
		printf("thread 1  value:%d\n",data++);
	}
	printf("thread 1 value:%p\n",&value);

	pthread_exit(&value);
}

int main(int argc, const char *argv[])
{
	int ret;
	int value=0;

	int *pval=NULL;

	pthread_t tid;

	ret =pthread_create(&tid,NULL,func,&value);
	if(ret!=0)
	{
		perror("Fail to pthread_create");
		return -1;
	}
	
	ret=pthread_join(tid,(void **)&pval);
	if(ret!=0)
	{
		fprintf(stderr,"Fail to pthread_join %s\n",strerror(errno));
		return -1;
	}
	printf("pval=%p value:%d\n",pval,*pval);
	pthread_exit(NULL);
	return 0;
}

4.创建分离式线程
int pthread_detach(pthread_t thread);//非阻塞
//功能:将线程标记为分离式线程
//参数:
//thread 线程的tid号
//返回值:成功返回0,失败返回错误码
(1)分离式线程的特点:线程结束时,系统会自动回收资源,不需要pthread_join()函数来阻塞回收;
//示例:

//创建线程后,在主线程添加
pthread_detach(tid);//把需要改成分离式线程的线程号填进去,这里看不到效果,子线程结束后,系统自动回收资源。

5.取消一个线程
int pthread_cancel(pthread_t thread);//取消一个线程的执行(取消别人)
//参数:
//thread 线程的tid号
//返回值:成功返回0,失败返回错误码
//示例:创建子线程,主线程休眠4秒取消子线程,并回收子线程资源。

#include<stdio.h>
#include<pthread.h>

void *func(void *arg)
{
	
	while(1)
	{
		sleep(1);
		printf("thread 1 running\n");
	}
pthread_exit(NULL);//
}
int main(int argc,const char *argv[])
{
	pthread_t tid;
	int ret;
	ret=pthread_create(&tid,NULL,func,NULL);
	if(ret!=0)
	{
		perror("Fail to pthread_create");
		return -1;
	}
	sleep(4);
	ret=pthread_cancel(tid);//取消子线程,成功返回0,失败返回错误码
	if(ret!=0)
	{
		perror("Fail to pthread_cance");
		return -1;
	}	
	pthread_exit(NULL);
}

//示例:打开一个文件,创建两个子进程,一个子进程写,一个子进程读并且打印,当读到"quit"时,退出子进程。

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int gTid;//其实可以通过传参把读线程的线程号传入写线程
void *func1(void *arg1)//read
{
	char buf[1024]={0};
	int fd=*(int *)arg1;
	while(1)
	{
		memset(buf,0,sizeof(buf));
		ssize_t ret=read(fd,buf,sizeof(buf));
		if(ret<0)
		{
			perror("Fail to read");
			return NULL;
		}
		else if(ret==0)
		{
			continue;
		}
		else
		{
			printf("p:%s\n",buf);
		}
	}
	pthread_exit(NULL);
}
void *func2(void *arg2)//write
{
	char buf[1024]={0};
	int fd=*(int *)arg2;
	while(1)
	{
		memset(buf,0,sizeof(buf));
		fgets(buf,sizeof(buf),stdin);

		buf[strlen(buf)-1]='\0';

		if(strncmp(buf,"quit",4)==0)
		{
			pthread_cancel(gTid);
			break;
		}
		write(fd,buf,strlen(buf));
		lseek(fd,-strlen(buf),SEEK_CUR);		
	}
	pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
	pthread_t tid1,tid2;
	int ret;
	int fd;
	if(argc!=2)
	{
		fprintf(stderr,"usage: %s log.txt",argv[0]);
		return -1;
	}
	fd=open(argv[1],O_RDWR|O_CREAT|O_TRUNC,0666);
	if(fd<0)
	{
		perror("Fail to open");
		return -1;
	}
	ret=pthread_create(&tid1,NULL,func1,&fd);//read
	if(ret!=0)
	{
		perror("Fail to pthread_create");
		return -1;
	}
	gTid=tid1;

	ret=pthread_create(&tid2,NULL,func2,&fd);
	if(ret!=0)
	{
		perror("Fail to pthread_create");
		return -1;
	}
	pthread_exit(NULL);
	return 0;
}

6.线程间同步,使用信号量
//功能:对于两个线程,创建两个(全局变量)信号量A,B(sem_t A,B),先对A,B赋初值,A 为1(sem_init(&A,0,1),B为0(sem_init(&B,0,0),在第一个线程中使用sem_wait(&A),当A为0时阻塞,当使用sem_post(&A)时,释放A,此时sem_wait(&A)可以顺利执行。
(1)建立全局变量的信号量:sem_t sem_A;
(2)初始化信号量:

int sem_init(sem_t *sem,int pshared,unsigned int value);
//返回值:成功返回0,失败返回-1
//参数:
//sem   第一步创建的 信号量;
//pshared   0:线程间使用
//value     信号量的初始值

(3)P操作

int sem_wait(sem_t *sem);
//功能:申请资源,如果资源为0则阻塞调用者
//返回值:成功返回0,失败返回-1
//参数:
//sem   :信号量的地址

(3)V操作

int sem_post(sem_t *sem);
//功能:释放资源,如果有线程等待则唤醒等待的线程
//返回值:成功返回0,失败返回-1
//参数:
//sem   :信号量的地址

//示例:

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
#include<semaphore.h>

sem_t sem_read,sem_write;
struct data_t
{
	char name[20];
	int id;
	int score;
};
struct data_t stu;

void *func1(void *arg1)//write
{
	char buf[1024]={0};
	while(1)
	{
		sem_wait(&sem_write);
		memset(&stu,0,sizeof(struct data_t));
		memset(buf,0,sizeof(buf));
		printf("name:");
		fgets(buf,sizeof(buf),stdin);
		fflush(stdin);
		buf[strlen(buf)-1]='\0';
		strcpy(stu.name,buf);
		
		if((stu.name,"quit",4)==0)
		{
			break;
		}
		printf("ID:");
		scanf("%d",&stu.id);
		getchar();
		printf("score:");
		scanf("%d",&stu.score);
		getchar();//取走换行符
		sem_post(&sem_read);
	}
	pthread_exit(NULL);
}
void *func2(void *arg2)
{
	while(1)
	{
		sem_wait(&sem_read);
		printf("name:%s   id:%d  score:%d\n",stu.name,stu.id,stu.score);
		sem_post(&sem_write);//释放信号量
	}
}

int main(int argc, const char *argv[])
{
	pthread_t tid1,tid2;
	int ret;
	sem_init(&sem_read,0,0);//初始化信号量
	sem_init(&sem_write,0,1);
	ret=pthread_create(&tid1,NULL,func1,NULL);
	if(ret!=0)
	{
		perror("Fail to create_thread");
		return -1;
	}
	ret=pthread_create(&tid2,NULL,func2,NULL);
	if(ret!=0)
	{
		perror("Fail to create_thread");
		return -1;
	}
	pthread_exit(NULL);
	return 0;
}

7.线程间互斥 --互斥锁
//功能:一个线程访问资源的时候,不允许其他线程访问;
宏创建互斥锁

pthread_mutex_t mutex=

(1)定义互斥锁

 pthread_mutex_t mlock;//定义了一个叫mlock的互斥锁

(2)初始化互斥锁

int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);
//返回值:成功返回0,失败返回-1
//参数:
//mutex  互斥锁地址
//attr   默认值NULL;

(3)获得互斥锁

int pthread_mutex_lock(pthread_mutex_t *mutex);
//功能:获得互斥锁则立即返回,否则阻塞直到获得互斥锁
//返回值:成功返回0,失败返回-1
//参数: mutex  互斥锁地址

(4)获得互斥锁

int pthread_mutex_unlock(pthread_mutex_t *mutex);
//功能:释放互斥锁
//返回值:成功返回0,失败返回-1
//参数: mutex  互斥锁地址

(5)销毁互斥锁

int pthread_mutex_destroy(pthread_mutex_t *mutex);
//功能:销毁互斥锁
//返回值:成功返回0,失败返回-1
//参数: mutex  互斥锁地址

//示例:

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
#include<stdlib.h>
int pro=0;
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;//定义互斥锁同时初始化
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;//定义条件变量同时初始化

void *func1(void *arg)
{
	int data;
	while(1)
	{
		
		pthread_mutex_lock(&mutex);//抢占互斥锁
		while(pro!=0)
		{
			pthread_cond_wait(&cond,&mutex);//	

		}

		data=rand()%100;
		pro=data;
		printf("producer:%d\n",pro);
		pthread_mutex_unlock(&mutex);//释放互斥锁
		pthread_cond_signal(&cond);
	
	}

	pthread_exit(NULL);

}

void *func2(void *arg)
{
	while(1)
	{
		pthread_mutex_lock(&mutex);//抢占互斥锁
	
		while(pro==0)
		{	
			pthread_cond_wait(&cond,&mutex);//	
		}
		printf("pro=%d\n",pro);
		pro=0;
		pthread_mutex_unlock(&mutex);//释放互斥锁
		pthread_cond_signal(&cond);


	}
	pthread_exit(NULL);
}


int main(int argc, const char *argv[])
{
	pthread_t tid1,tid2;

	int ret;

	ret=pthread_create(&tid1,NULL,func1,NULL);
	if(ret!=0)
	{
		perror("Fail to pthread_create");
		return -1;
	}

	ret=pthread_create(&tid2,NULL,func2,NULL);
	if(ret!=0)
	{
		perror("Fail to pthread_create");
		return -1;
	}


	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
	
	pthread_exit(NULL);
	pthread_mutex_destroy(&mutex);
	return 0;
}

8.条件变量
(1)定义:条件变量是利用线程间共享的全局变量进行同步通信的一种机制。多个线程等待某一个条件满足,在条件达到时由一个线程去通知其他等待的线程。
(2)条件变量相关函数。

pthread_cont_t cond;//定义条件变量
pthread_cont_init(&cond,NULL);//动态初始化条件变量

//等待条件变量,条件不满足,则阻塞当前进程,
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);

//唤醒条件变量
int pthread_cond_broadcast(pthread_cond_t *cond);//唤醒所有等待的线程
int pthread_cond_signal(pthread_cond_t *cond);//唤醒至少一个等待线程

//销毁条件变量
pthread_cond_destroy(pthread_cond_t *cond);

//示例:见互斥锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jun8086

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值