线程的资源保护机制

1.互斥锁
互斥锁的使用:
定义锁:pthread_mutex_t mutex
初始化锁:int pthread_mutex_init(&mutex,NULL)
加锁:int pthread_mutex_lock(阻塞加锁)
int pthread_mutex_trylock(在锁被占用时,返回EBUSY,而不是挂起等待)
解锁:int pthread_mutex_unlock(&mutex)
销毁:int pthread_mutex_destroy(&mutex)

**注意:多线程的互斥因为没有使用互斥锁,会导致在一个线程写完11111后跑到另一个线程写33333。使用互斥锁,可以避免这种情况发生。

1)采用全局变量

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>

#define N 10000

pthread_mutex_t mutex;  

void* task1(void * arg)
{
	int i = 0;
    int fd = *((int*)arg);

	while(i++ < N){
		pthread_mutex_lock(&mutex);
		write(fd,"11111",5);
		write(fd,"22222\n",6);
		pthread_mutex_unlock(&mutex);
	}
	return NULL;
}

void* task2(void * arg)
{
	int i = 0;
     int fd = *((int*)arg);

		while(i++ < N){
			pthread_mutex_lock(&mutex);
			write(fd,"33333",5);
			write(fd,"44444\n",6);
			pthread_mutex_unlock(&mutex);
		}
		return NULL;
	}


int main(){


	pthread_t tid1,tid2;

	int fd;

	fd = open("/home/ben/c.d/t1.txt",O_RDWR|O_CREAT|O_APPEND,0755);
	if(fd == -1){
		printf("open the file fail");
		exit(1);
	}else{
		printf("open successful!\n");
	}

	pthread_mutex_init(&mutex,NULL);


	if(pthread_create(&tid1,NULL,task1,&fd)){
		perror("pthread_create error!");
		exit(1);
	}
	printf("create thread successful!  tid1=%ld\n",tid1);

	if(pthread_create(&tid2,NULL,task2,&fd) != 0){
		perror("pthread_create error!");
		exit(1);
	}
	printf("create thread successful!tid2=%ld\n",tid2);

	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
	printf("main join successful!\n");

    pthread_mutex_destroy(&mutex);
    printf("end...");
    close(fd);
	return 0;
}

2)采用参数传递

用结构体定义的变量叫结构体变量,如:
struct student stu; //定义一个结构体变量stu
这种变量在引用结构体成员时,使用点(.)来操作。

结构体类型也可以定义指针变量,如:
struct student *pstu; //定义一个结构体指针变量pstu
pstu=&stu ; //pstu指针指向stu结构体变量
结构体指针变量在引用成员变量时,使用箭头(->)来操作。

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>

#define N 10000


typedef struct{
	pthread_mutex_t mutex;
	int fd;
}Msg;

void* task1(void * arg)
{
	Msg * msgp = (Msg*)arg;  //这里的参数是一个指针变量,所有我们定义的结构体变量是指针型的
	int fd = msgp->fd;
	int i = 0;

	while(i++ < N){
		pthread_mutex_lock(&msgp->mutex);
		write(fd,"11111",5);
		write(fd,"22222\n",6);
		pthread_mutex_unlock(&msgp->mutex);
	}
	return NULL;
}

void* task2(void * arg)
{
	Msg * msgp = (Msg*)arg;
	int fd = msgp->fd;
	int i = 0;

		while(i++ < N){
			pthread_mutex_lock(&msgp->mutex);
			write(fd,"33333",5);
			write(fd,"44444\n",6);
			pthread_mutex_unlock(&msgp->mutex);
		}
		return NULL;
	}


int main(){

	int fd = open("/home/ben/c.d/t.txt",O_RDWR|O_CREAT|O_APPEND,0755);
		if(fd == -1){
			printf("open the file fail");
			exit(1);
		}else{
			printf("open successful!\n");
		}
	Msg msg;
	msg.fd = fd;
	pthread_t tid1,tid2;


			fd = open("/home/ben/c.d/t.txt",O_RDWR|O_CREAT|O_APPEND,0755);
			if(fd == -1){
				printf("open the file fail");
				exit(1);
			}else{
				printf("open successful!\n");
			}

			pthread_mutex_init(&msg.mutex,NULL);


	if(pthread_create(&tid1,NULL,task1,&msg)){
		perror("pthread_create error!");
		exit(1);
	}
	printf("create thread successful!  tid1=%ld\n",tid1);

	if(pthread_create(&tid2,NULL,task2,&msg) != 0){
		perror("pthread_create error!");
		exit(1);
	}
	printf("create thread successful!tid2=%ld\n",tid2);

	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
	printf("main join successful!\n");

    pthread_mutex_destroy(&msg.mutex);
    printf("end...");
    close(fd);
	return 0;
}

2.线程信号量

使用步骤
1)声明信号量:可以一起声明多个:sem_t 或 sem[n]
2)初始化信号量:sem_init(&sem,0,1) //第二个参数必须为0,表示这里是线程的信号量,为1表示进程的信号量,但还未实现有bug。
3)P操作:sem_wait(&sem)
4)V操作:sem_post(&sem)
5)删除信号量:sem_destroy(&sem)

加信号量互斥—实现互斥取款

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>

int balance = 10;


 sem_t sem1;

void* task11(void * arg)
{
	while(balance > 0){
		sem_wait(&sem1);
		if(balance > 0){
			printf("task11:before draw money,balance is %d\n",balance);
			balance--;
			printf("task11:after draw money,balance is %d\n",balance);
		}
		sem_post(&sem1);
		sleep(1);
	}
	return NULL;
}

void* task22(void * arg)
{
	while(balance > 0){
		sem_wait(&sem1);
		if(balance > 0){
				printf("task22:before draw money,balance is %d\n",balance);
				balance--;
				printf("task22:after draw money,balance is %d\n",balance);
			}
		sem_post(&sem1);
		sleep(1);
		}
		return NULL;
	}


int main(){

		sem_init(&sem1,0,1);
		pthread_t tid1,tid2;

		int fd;

		fd = open("/home/ben/c.d/t.txt",O_RDWR|O_CREAT|O_APPEND,0755);
		if(fd == -1){
			printf("open the file fail");
			exit(1);
		}else{
			printf("open successful!\n");
		}

		if(pthread_create(&tid1,NULL,task11,&fd)){
			perror("pthread_create error!");
			exit(1);
		}
		printf("create thread successful!  tid1=%ld\n",tid1);

		if(pthread_create(&tid2,NULL,task22,&fd) != 0){
			perror("pthread_create error!");
			exit(1);
		}
		printf("create thread successful!tid2=%ld\n",tid2);

		pthread_join(tid1,NULL);
		pthread_join(tid2,NULL);
		printf("main join successful!\n");

		printf("end...");
		close(fd);
		return 0;
}

加信号量实现同步

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>


 sem_t sem[3];

void* task1(void * arg)
{
	while(1){
		sem_wait(&sem[0]);
		printf("1\n");
		sleep(1);
		sem_post(&sem[1]);
	}
	return NULL;
}

void* task2(void * arg)
{
	while(1){
		sem_wait(&sem[1]);
		printf("2\n");
		sleep(1);
		sem_post(&sem[2]);
		}
		return NULL;
	}

void* task3(void * arg)
{
	while(1){
		sem_wait(&sem[2]);
		printf("3\n");
		sleep(1);
		sem_post(&sem[0]);
		}
		return NULL;
	}

int main(){

		sem_init(&sem[0],0,1);
		sem_init(&sem[1],0,0);
		sem_init(&sem[2],0,0);
		pthread_t tid1,tid2,tid3;


		if(pthread_create(&tid1,NULL,task1,NULL)){
			perror("pthread_create error!");
			exit(1);
		}
		printf("create thread successful! tid1=%ld\n",tid1);

		if(pthread_create(&tid2,NULL,task2,NULL) != 0){
			perror("pthread_create error!");
			exit(1);
		}
		printf("create thread successful! tid2=%ld\n",tid2);

		if(pthread_create(&tid3,NULL,task3,NULL) != 0){
				perror("pthread_create error!");
				exit(1);
			}
			printf("create thread successful! tid3=%ld\n",tid3);

		pthread_join(tid1,NULL);
		pthread_join(tid2,NULL);
		pthread_join(tid3,NULL);
		printf("main join successful!\n");


		return 0;
}

互斥锁与信号量的区别
Mutex 是一把钥匙,一个人拿了就可以进入一个房间,出来的时候把钥匙交给队列的第一个。
Semaphore是一件可以容纳N人的房间,如果人不满就可以进去,如果人满了,就要等待有人出来。队友N=1的情况,称为binarary semaphore。

Binary semaphore与Mutex的差异:
1.mutex要由获得锁的线程来释放(谁获得谁释放)。而semaphore可以由其他线程释放。
2.初始状态可能不一样:mutex的初始值为1,semaphore可能是0(或者是1)。

互斥信号量+条件变量

例题:有一个盘子,其中最多可以放6个馒头。有若干个生产者不断生产馒头,并放在盘子中,但不能超过6个。如果已经满6个,试图生产的生产者将会等待,直到盘中的馒头少于6个后再生产。同时,有若干个消费者,不断来消费盘中的馒头,盘中馒头不能少于0个。如果已经为0个,试图消费的消费者将会等待,直到盘中的馒头大于0个时再消费。
:(一个生产者生产时另外一个生产者就不能生产,其他消费者也不能消费,同理一个消费者消费时,另一个消费者不能消费,生产者不能生产)

pthread_cond_wait总和一个互斥锁结合使用。在调用pthread_cond_wait前要先获取锁。pthread_cond_wait函数执行时先自动释放指定的锁,然后等待条件变量的变化。在函数调用返回之前,自动将指定的互斥量重新锁住。
int pthread_cond_signal(pthread_cond_t * cond);
pthread_cond_signal通过条件变量cond发送消息,若多个消息在等待,它只唤醒一个。pthread_cond_broadcast可以唤醒所有。调用pthread_cond_signal后要立刻释放互斥锁,因为pthread_cond_wait的最后一步是要将指定的互斥量重新锁住,如果pthread_cond_signal之后没有释放互斥锁,pthread_cond_wait仍然要阻塞。

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

int n = 0;// 0 <= n <= 6

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t wait_produce = PTHREAD_COND_INITIALIZER;
pthread_cond_t wait_consume = PTHREAD_COND_INITIALIZER;


void *producer(void * arg){
	while(1){
		char *i = arg;
		pthread_mutex_lock(&mutex); //生产者获得锁
		if(n == 6){
			pthread_cond_wait(&wait_produce,&mutex);//生产者等待生产,并释放锁,进入消费者消费模式
		}
		if(n < 6){
			printf("%s before produce:n = %d\n",i,n);
			n++;
			printf("%s after produce:n = %d\n",i,n);
		}
		pthread_cond_signal(&wait_consume); //唤醒消费者
		pthread_mutex_unlock(&mutex);
	//	usleep(1);
	}
	pthread_exit(NULL);
}
void *comsumer(void * arg){
	while(1){
		char *i = arg;
		pthread_mutex_lock(&mutex); //消费者获得锁
		if(n == 0){
			pthread_cond_signal(&wait_produce); //唤醒生产者
			pthread_cond_wait(&wait_consume,&mutex); //消费者等待消费,并释放锁
		}
		if(n > 0){
			printf("%s before consumer:n = %d\n",i,n);
			n--;
			printf("%s after comsumer:n = %d\n",i,n);
		}
		pthread_mutex_unlock(&mutex); //解锁
//		usleep(1);
	}
	pthread_exit(NULL);
}


int main(){
	pthread_t cid1,cid2;
	pthread_t pid1,pid2;
	if(pthread_create(&cid1,NULL,comsumer,"c1") != 0){
		perror("pthread create c1 error\n");
	}
	if(pthread_create(&cid2,NULL,comsumer,"c2") != 0){
			perror("pthread create c2 error\n");
		}
	if(pthread_create(&pid1,NULL,producer,"p1") != 0){
			perror("pthread create p1 error\n");
		}
	if(pthread_create(&pid2,NULL,producer,"p2") != 0){
			perror("pthread create p2 error\n");
		}

	pthread_join(cid1,NULL);
	pthread_join(cid2,NULL);
	pthread_join(pid1,NULL);
	pthread_join(pid2,NULL);
	//destroy pthread_cond
	pthread_cond_destroy(&wait_produce);
	pthread_cond_destroy(&wait_consume);
	pthread_mutex_destroy(&mutex);

	pthread_exit(NULL);
	printf("main is over!\n");

}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值