Linux 多线程编程

@

线程ID

在这里插入图片描述

创建一个新的线程:

在这里插入图片描述
创建新线程:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h> 

struct message{
	int i;
	char j[20];

};

void *thread_func(void *s){
	printf("i = %d h = %s \n",((struct message *)s)->i,((struct message *)s)->j);
	return(void *)0;
}

int main(int argc,char *argv[]){
	pthread_t newtid;
	int err;
	struct message msg;
	msg.i=10;
	memcpy(msg.j,"aaaa",20);
	
	err = pthread_create(&newtid,NULL,thread_func,(void *)(&msg));
	
	if(err!=0){
		printf("创建新线程失败 \n");
		return 0;
	}
	
	for(int i=0;i<argc;i++ ){
		printf("main thread agrs is %s \n",argv[i]);
	}
	sleep(2);
	
	return 0;
}
}
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h> 

void print_id(char *s){
	pid_t pid;
	pthread_t tid;
	
	pid = getpid();
	tid = pthread_self();
	
	printf("%s pid is %u, tid is 0x%x",s,pid,tid);
	
}
void *thread_fun(void *arg){
	print_id(arg);
	return(void *)0;
}
int main(){
	pthread_t newtid;
	int err;
	err = pthread_create(&newtid,NULL,thread_fun,"new thread")
	
	if(err!=0){
		printf("创建新线程失败");
		return 0;
	}
	
	print_id("main thread:");
	sleep(2);
	
	return 0;
}

线程的四个状态

在这里插入图片描述

线程的退出

在这里插入图片描述

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h>
//////////三种退出方式
void *thread_fun(void *arg){
	if(strcmp("1",(char*)arg)==0){
		printf("new thread trurn !\n");
		return (void *)1;             //不会退出进程
	}

	if(strcmp("2",(char*)arg)==0){
		printf("new thread prhread_exit !\n");		//不会退出进程
		pthread_exit((void*)2);
	}	
	if(strcmp("3",(char*)arg)==0){				//会导致进程推出,主线程关闭
		printf("new thread exit !\n");
		exit(3);
	}
}

int main(int argc,char *argv[]){
	int err;
	pthread_t tid;
	err = pthread_create(&tid,NULL,thread_fun,(void *)argv[1]);
	if (err!=0){
		printf("create failed \n");
		return 0;
	}
	sleep(1);
	printf("main thread exit \n");
	return 0;

}

连接线程

函数pthread_join用来等待一个线程的结束,线程间同步的操作。

int pthread_join(pthread_t thread, void **value_ptr);
thread:等待退出线程的线程号。
value_ptr:退出线程的返回值。
在这里插入图片描述

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h>

void *thread_fun1(void *arg){
	printf("I am the first thread \n");
	return(void *)1;
}

void *thread_fun2(void *arg){
	printf("I am the first thread \n");
	pthread_detach(pthread_self());  //分离
	pthread_exit((void *)2);       /////已经分离无法连接
}

int main(int argc,char *argv[]){

	int err1;
	int err2;
	pthread_t tid1;
	pthread_t tid2;
	void *rval1, *rval2; 

	err1 = pthread_create(&tid1,NULL,thread_fun1,NULL); 
	err2 = pthread_create(&tid1,NULL,thread_fun2,NULL); 
	if (err1 || err2){
		printf("create failed \n");
		return 0;
	}
	printf("this is main thread\n");
	printf("join 1  raval:%d\n",pthread_join(tid1,&rval1));
	printf("join 2  raval:%d\n",pthread_join(tid2,&rval2));   //连接错误

	/////////////返回函数保存在raval中

	printf("thread 1 exit code is:%d\n",(int *)rval1); 
	printf("thread 2 exit code is:%d\n",(int *)rval2); 	
	sleep(1);
	return 0;



}

线程的取消

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
取消操作
在这里插入图片描述

信号默认处理

在这里插入图片描述
在这里插入图片描述

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h> 

void *thread_fun(void *arg){
	sleep(1);
	printf("this is new thread \n");
	return (void *)0;
}
int main(){
	pthread_t tid;
	int err;
	int s;
	void *rval;
	err = pthread_create(&tid,NULL,thread_fun,NULL);
	if(err!=0){
		printf("erro! \n");
		trturn;
	}
//	sleep(1);
	s = pthread_kill(tid,SIGQUIT);   //终止线进程的运行信号 
	if(s == ESRCH){	//如果线程已经退出  返回为ESRCH 
		printf("thread  tid is nor found \n");
	}
	
	pthread_join(tid,&rval);
	return 0;
}

在这里插入图片描述

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include<signal.h>
#include <sys/syscall.h> 

void sig_hander1(int arg){
	printf("Thread 1 get signal \n");
	return;
} 

void sig_hander2(int arg){
	printf("Thread 2 get signal \n");
	return;
} 



void *thread_fun1(void * arg){
	printf(" new thread 1 \n");
	struct sigaction act;
	memset(&act,0,sizeof(act));
	act.sa_handler = sig_hander1;
	sigaddset(&act.sa_mask,SIGQUIT);
	sigaction(SIGQUIT,&act,NULL);
	pthread_sigmask(SIG_BLOCK,&act.sa_mask,NULL);
	sleep(2);
}



void *thread_fun2(void * arg){
	printf(" new thread 2 \n");
	struct sigaction act;
	memset(&act,0,sizeof(act));
	sigaddset(&act.sa_mask,SIGQUIT);
	act.sa_handler = sig_hander2;
	sigaction(SIGQUIT,&act,NULL);
//	pthread_sigmask(SIG_BLOCK,&act.sa_mask,NULL);
	sleep(2);
}



int main(){
	pthread_t tid1,tid2;
	int err,s;
	void *rval1,*rval2;
	err = pthread_create(&tid1,NULL,thread_fun1,NULL);
	if(err!=0){
		printf("erro! \n");
	}
	err = pthread_create(&tid2,NULL,thread_fun2,NULL);
	if(err!=0){
		printf("erro! \n");
	}
	sleep(1);
	s = pthread_kill(tid1,SIGQUIT);
	if(s!=0){
		printf("send signal erro \n");
	}
	s = pthread_kill(tid2,SIGQUIT);
	if(s!=0){
		printf("send signal erro \n");
	}	
	pthread_join(tid1,&rval1);
	pthread_join(tid2,&rval2);
	
	return 0;
} 

线程清理程序

在这里插入图片描述

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h> 
#include <signal.h>

void *first_clean(void *arg){
	printf(" first clean \n");
	return (void *)0;
}

void *second_clean(void *arg){
	printf(" secend clean \n");
	return (void *)0;
}

void *thread_fun1(void * arg){
	printf("new thread 1 \n");
	pthread_cleanup_push(first_clean,"thread1");
	pthread_cleanup_push(second_clean,"thread1");
	
	pthread_cleanup_pop(1);    //先注册后执行
	pthread_cleanup_pop(0);
	return (void *)1;

}

void *thread_fun2(void * arg){

	printf("new thread 2 \n");
	pthread_cleanup_push(first_clean,"thread12");
	pthread_cleanup_push(second_clean,"thread2");
	pthread_cleanup_pop(0);
	pthread_cleanup_pop(0);
	pthread_exit((void *)2);
}

int main(){

	pthread_t tid1,tid2;
	int err;
	err = pthread_create(&tid1,NULL,thread_fun1,NULL);
	if(err!=0){
		printf(" create erro \n");
		return;
	}
	err = pthread_create(&tid2,NULL,thread_fun2,NULL);
	if(err!=0){
		printf(" create erro \n");
		return;
	}
	sleep(2);
	return 0;
}

互斥操作的必要性

在这里插入图片描述

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h> 
#include <signal.h>

struct student{
	int age;
	int id;
}stu;
int i;
void *thread_fun1(void *arg){
	while(1){
		stu.age = i;
		stu.id = i;
		i++;
		if(stu.age!=stu.id){
		printf("%d  %d\n",stu.age,stu.id);
		break;
		}
	}	
	return (void *)1;
} 
void *thread_fun2(void *arg){
	while(1){
		stu.age = i;
		stu.id = i;
		i++;
		if(stu.age!=stu.id){
		printf("%d  %d\n",stu.age,stu.id);
		break;
		}
	}
	return(void*)1;
} 

int main(){
	pthread_t tid1,tid2;
	int err;
	err = pthread_create(&tid1,NULL,thread_fun1,NULL);
	if(err!=0){
		printf("erro \n");
		return;
	}
	err = pthread_create(&tid2,NULL,thread_fun2,NULL);
	if(err!=0){
		printf("erro \n");
		return;
	}
	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
	return 0;
}

在这里插入图片描述

互斥量

其本身为一个锁
在这里插入图片描述

加锁解锁

在这里插入图片描述

///////将会一直运行下去
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h> 
#include <signal.h>

struct student{
	int age;
	int id;
}stu;
int i;
pthread_mutex_t mutex;
void *thread_fun1(void *arg){

	while(1){
		pthread_mutex_lock(&mutex);
		stu.age = i;
		stu.id = i;
		i++;
		if(stu.age!=stu.id){
			printf("%d  %d",stu.age,stu.id);
			break;
		}	
		pthread_mutex_unlock(&mutex);
	}
	return (void *)1;
} 

void *thread_fun2(void *arg){
	while(1){
		pthread_mutex_lock(&mutex);
		stu.age = i;
		stu.id = i;
		i++;
		if(stu.age!=stu.id){
			printf("%d  %d",stu.age,stu.id);
			break;
		}	
		pthread_mutex_unlock(&mutex);
	}	
	return(void*)1;
} 

int main(){
	pthread_t tid1,tid2;
	int err;
	err = pthread_mutex_init(&mutex,NULL);
	if(err!=0){
		printf("init mutex erro \n");
		return;
	}
	err = pthread_create(&tid1,NULL,thread_fun1,NULL);
	if(err!=0){
		printf("1 erro \n");
		return;
	}
	err = pthread_create(&tid2,NULL,thread_fun2,NULL);
	if(err!=0){
		printf("2 erro \n");
		return;
	}
	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
	return 0;
}

读写锁

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

读写锁是用来解决读者写者问题的,读操作可以共享,写操作是排他的,读可以有多个在读,写只有唯一个在写,同时写的时候不允许读。

互斥锁与读写锁的区别:

当访问临界区资源时(访问的含义包括所有的操作:读和写),需要上互斥锁;

当对数据(互斥锁中的临界区资源)进行读取时,需要上读取锁,当对数据进行写入时,需要上写入锁。

读写锁的优点:

对于读数据比修改数据频繁的应用,用读写锁代替互斥锁可以提高效率。因为使用互斥锁时,即使是读出数据(相当于操作临界区资源)都要上互斥锁,而采用读写锁,则可以在任一时刻允许多个读出者存在,提高了更高的并发度,同时在某个写入者修改数据期间保护该数据,以免任何其它读出者或写入者的干扰。

读写锁描述:

获取一个读写锁用于读称为共享锁,获取一个读写锁用于写称为独占锁,因此这种对于某个给定资源的共享访问也称为共享-独占上锁。

有关这种类型问题(多个读出者和一个写入者)的其它说法有读出者与写入者问题以及多读出者-单写入者锁。



#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h> 
#include <signal.h>

int num = 0;
pthread_rwlock_t rwlock;

void *thread_fun1(void *arg){
	int err;
	pthread_rwlock_rdlock(&rwlock);		//读加锁 
	printf("thread 1 print num:%d\n",num);
	sleep(3);
	printf("Thread 1 over \n");
	pthread_rwlock_unlock(&rwlock);		//读解锁 
	return(void *)1;
}
void *thread_fun2(void *arg){
	int err;
	pthread_rwlock_rdlock(&rwlock);
	printf("thread 2 print num:%d\n",num);
	sleep(3);
	printf("Thread 2 over \n");
	pthread_rwlock_unlock(&rwlock);
	return(void *)1;
}

int main(){
	pthread_t tid1,tid2;
	int err;
	err = pthread_rwlock_init(&rwlock,NULL);
	if(err!=0){
		printf(" create lock erro \n");
		return;	
	}
	err = pthread_create(&tid1,NULL,thread_fun1,NULL);
	if(err!=0){
		printf(" create thread 1 erro \n");
		return;
	}
	err = pthread_create(&tid2,NULL,thread_fun2,NULL);
	if(err!=0){
		printf(" create thread 2 erro \n");
		return;
	}
	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
	pthread_rwlock_destroy(&rwlock);
	
	return 0;
}

条件变量

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
》》》生产者与消费者算法》》》

///////////////////////////////
//这个老师的存取算法存在 bug,待改
//////////////////////////////

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h> 
#include <signal.h>

#define BUFFER_SIZE 4
#define PRODUC_CNT 20  

struct product_cons{
	int buffer[BUFFER_SIZE];	//仓库大小 
	pthread_mutex_t mutex;		//互斥锁 
	int writePoi,readPoi;		//读写位置 
	pthread_cond_t noEmpty;		//条件变量,非空&非满 
	pthread_cond_t noFull;
}buffer;

////////////////////初始化
void init(struct product_cons *p){      
	pthread_mutex_init(&p->mutex,NULL);
	pthread_cond_init(&p->noEmpty,NULL);
	pthread_cond_init(&p->noFull,NULL);
	p->readPoi=0;
	p->writePoi=0;
} 

/////////////////结束												
void finish(struct product_cons *p){		 
	pthread_mutex_destroy(&p->mutex);
	pthread_cond_destroy(&p->noEmpty);
	pthread_cond_destroy(&p->noFull);
	p->readPoi=0;
	p->writePoi=0;		
} 

////////////////存储数据到buffer
void put(struct product_cons *p,int data){
	pthread_mutex_lock(&p->mutex);
	if((p->readPoi+1)%BUFFER_SIZE==p->readPoi){
		printf("producer wait for coustorm...\n");
		pthread_cond_wait(&p->noFull,&p->mutex);
	}
	p->buffer[p->writePoi] = data;
	p->writePoi++;
	if(p->writePoi>=BUFFER_SIZE){
		p->writePoi = 0;
	}
	pthread_cond_signal(&p->noEmpty);
	pthread_mutex_unlock(&p->mutex);
}

///////////////移除数据从buffer 
int get(struct product_cons *p){
	int data;
	pthread_mutex_lock(&p->mutex);
	if(p->readPoi==p->writePoi){
		printf("customer wait product... \n");
		pthread_cond_wait(&p->noEmpty,&p->mutex);
	}
	data = p->buffer[p->readPoi];
	p->readPoi++;
	if(p->readPoi==BUFFER_SIZE){
		p->readPoi=0;
	}
	pthread_cond_signal(&p->noFull);
	pthread_mutex_unlock(&p->mutex);
	return data;
}

///////////////子线程   生产产品 
void *product(void *data){
	int n;
	for(n=1;n<=PRODUC_CNT;n++){
		sleep(1);
		printf("product the %d \n",n);
		put(&buffer,n);
		printf("put the %d produce into buffer \n",n);
	} 
	printf("the product thread success \n");
	return NULL;
}
//////////////子线程	消费产品 
void *customer(void *data){
	static int cnt = 0;			//子程序中的静态变量当离开子程序时仍存在,因此当再次进入时可以直接使用原来的值
	int num;
	while(1){
		sleep(2);
		printf("get the produce ...\n");
		num = get(&buffer);
		printf("get the product %d success\n",num);
		printf("################test#####%d\n",cnt);
		if(++cnt==PRODUC_CNT){
			break;
		} 
	}
	printf("custorm stopped \n");
	return NULL;
}
int main(int argc, char *argv[]){
	pthread_t tidp,tidc;
	void *rval;
	init(&buffer);
	pthread_create(&tidp,NULL,product,NULL);
	pthread_create(&tidc,NULL,customer,NULL);
	pthread_join(tidp,&rval);
	pthread_join(tidc,&rval);
	finish(&buffer);
	return 0;

}
posted @ 2021-06-08 14:23  剪水行舟  阅读(58)  评论(0)    收藏  举报