多线程和获取系统时间

死锁

多个线程之间使用互斥锁,每把互斥锁都处于上锁态,每把互斥锁又都需要另外的线程运行后才能解锁。

死锁的解决方式

pthread_mutex_trylock函数

函数原型:

int pthread_mutex_trylock(pthread_mutex_t *mutex);

功能:

尝试上锁互斥锁,如果该互斥锁已经上锁,则尝试上锁失败

返回值:

成功上锁返回0,失败返回错误码

互斥锁的属性

快速锁:

默认的互斥锁(第一次调用lock不会阻塞,第二次调用就会阻塞,第三次开始调用lock就会死锁)

递归锁:

第一次调用lock不会阻塞,第二次调用就会阻塞,第三次调用lock开始,返回0,并在互斥锁内部记录lock次数。(当互斥锁解锁时,只有解锁与lock次数相同的次数,才能解锁成功)

错误检查锁:

第一次调用lock不会阻塞,第二次调用就会阻塞,第三次调用lock开始,每次调用lock都会返回错误码

递归锁和错误检查锁都是为了防止死锁,只是应用场景不一样(快速锁可以通过trylock函数实现防止死锁)

递归锁的创建方式

静态创建

pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;

动态创建:

  1. 创建一个互斥锁属性变量

pthread_mutexattr_t attr;

  1. 初始化一个互斥锁属性变量

pthread_mutexattr_init (&attr);

  1. 及那个互斥锁的属性设置为递归锁

pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE_NP);

  1. 初始化互斥锁

pthread_mutex_init(&mutex,&attr);

错误检查锁的创建方式

静态创建

pthread_mutex_terrchkmutex=PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;

动态创建:

  1. 创建一个互斥锁属性变量

pthread_mutexattr_t attr;

  1. 初始化一个互斥锁属性变量

pthread_mutexattr_init (&attr);

  1. 及那个互斥锁的属性设置为错误检查锁

pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_ERRORCHECK_NP);

  1. 初始化互斥锁

pthread_mutex_init(&mutex,&attr);

无名信号量

无名信号量与互斥锁工作方式90%相同

区别:

无名信号量的值为0~n

互斥锁的值为0~1

互斥锁第二次上锁就会阻塞

无名信号量,根据信号量的值来决定第几次上锁才会阻塞

无名信号量的操作流程

  1. 创建无名信号量变量

sem_t sem;

  1. 初始化无名信号量

函数原型:

int sem_init(sem_t *sem, int pshared, unsigned int value);

调用形式:

sem_init(&sem,0,0/1/2/3/4/.....)

功能:

初始化无名信号量sem,并且设置初始值为value

参数 sem:等待初始化的无名信号量

参数 pshared:

0:表示在一个进程的多线程间共享,此时要求无名信号量所处的内存能够被所有线程访问

非0:表示在多个进程间共享,此时要求无名信号量申请在共享内存区域

参数value:无名信号量的初始值

仅当无名信号量的value为0时,再次上锁,无名信号量才会产生阻塞

  1. 获取/释放无名信号量(上锁/解锁)

获取无名信号量的value-1

函数原型:

int sem_wait(sem_t *sem);

调用形式:

sem_wait(&sem) ;

功能:

获取信号量中的一个资源,即信号量的value-1,如果当前信号量的value==0的话,则wait函数阻塞

函数原型:

int sem_trywait(sem_t *sem);

调用形式:

sem_trywait(&sem);

功能:

尝试获取信号量中的一个资源,如果当前信号量的value==0的话,则尝试失败,返回-1,获取成功,返回0

*没用递归信号量和错误检查信号量,trywait是防止死锁的唯一手段

释放无名信号量的value+1

函数原型:

int sem_post(sem_t *sem);

调用形式:

sem_post(&sem);

功能:

释放信号量中的一个资源,即信号量的value+1(可以一直加,超过初始值也可以)

无名信号量:互斥

无名信号量:同步

条件变量

在多线程中,只负责同步,不负责互斥

什么是条件变量

在多线程中,专门负责用来判断,当前线程是否满足运行条件

工作逻辑为:

线程1:无论是否满足运行条件,总是询问是否满足条件,只要询问了,就会阻塞(因为要等回复)

线程1只负责问,问谁无所谓

线程2:仅当线程1满足运行条件的情况下,才应该回复线程1,你满足条件了

场景举例

线程1:每次消费3个苹果
线程2:每次生产1个苹果

线程1每次消费之前,都会提问是否拥有3个苹果,只要问了就阻塞,哪怕现在有3个苹果也要问,问了也会阻塞

线程2每次生产完苹果之后,判断当前苹果数量是否达到了3个,如果达到了3个,就会通知线程1,允许消费苹果。此时线程1就会解除阻塞,正常消费苹果

条件变量的创建流程

创建条件变量和互斥锁

pthread_cond_t cond
pthread_mutex_t mutex

初始化条件变量和互斥锁

函数原型:
int pthread_cond_init(pthread_cond_t* cond,pthread_condattr_t*cond_attr);
调用形式:
pthread_cond_init(&cond,0);
    功能描述:初始化条件变量
    参数 cond:等待初始化的条件变量的地址
    参数 cond_attr:这里只能传0,表示默认属性

pthread_mutex_init(&mutex,0)

条件询问,产生阻塞

函数原型:
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
调用形式:
pthread_cond_wait(&cond,&mutex)
   功能:询问条件是否满足,阻塞等待回复
   以为条件变量不负责保护临界资源,所以一定要互斥锁来保护临界资源的安全
   wait会自动解锁互斥锁以避免死锁。

回答询问,条件唤醒,解除阻塞

函数原型:
int pthread_cond_signal(pthread_cond_t *cond);
调用形式:
pthread_cond_signal(&cond)
 功能描述:回答wait的问题,唤醒因为wait而产生阻塞的线程
 如果多个线程都以为wait而阻塞,一个signal只能唤醒一个wait
 此时多个wait会抢夺一个signal,谁抢到谁运行

函数原型:
int pthread_cond_broadcast(pthread_cond_t *cond);
调用形式:
pthread_cond_broadcast(&cond)
功能:唤醒当前线程中,所有被wait阻塞的线程,先wait的优先唤醒

被唤醒的wait会自动锁上那把互斥锁

当不再使用条件变量时,销毁条件变量

函数原型:
int pthread_cond_destroy(pthread_cond_t *cond);
调用形式:
pthread_cond_destroy(&cond)
功能:销毁条件变量

练习:

有两个线程

1#线程负责每秒生产一个苹果

2#线程负责每秒消费3个苹果

要求使用条件变量使得用户买到正常数量苹果(苹果不会越来越多,也不会变为负数)

 #include <stdio.h>
#include <string.h>
#include <stdlib.h>	
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>

typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;

pthread_cond_t c;
pthread_mutex_t m;
int a=0;

void* task1(void* arg)
{	
	while(1)
	{
		pthread_mutex_lock(&m);
		pthread_cond_wait(&c,&m);
		a-=3;
		printf("顾客买了3个苹果,还剩%d个苹果\n",a);
		sleep(1);
		pthread_mutex_unlock(&m);
	}

}

int main(int argc, const char *argv[])
{
	pthread_cond_init(&c,0);
	pthread_mutex_init(&m,0);

	pthread_t id1;
	pthread_create(&id1,0,task1,0);

	pthread_detach(id1);

	int i;
	while(1)
	{
		pthread_mutex_lock(&m);
		a++;
		printf("有%d个苹果\n",a);
		if(a>=3)
		{
			pthread_cond_signal(&c);
		}
		else
		{
			printf("不满足客服购买需求\n");
		}
		pthread_mutex_unlock(&m);
		sleep(1);

	}

	return 0;
}

有三个线程

1#线程负责每秒消费3个苹果

2#线程负责每2秒消费5个橘子

3#线程每秒生成1个苹果或2个橘子

#include <stdio.h>
#include <string.h>
#include <stdlib.h>	
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>

typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;

pthread_cond_t c;
pthread_cond_t d;
pthread_mutex_t m;
int a=0;
int b=0;
int sec=0;

void* task1(void* arg)
{	
	while(1)
	{
		pthread_mutex_lock(&m);
		pthread_cond_wait(&c,&m);
		a-=3;
		printf("顾客买了3个苹果,还剩%d个苹果\n",a);
		sleep(1);
		pthread_mutex_unlock(&m);
	}

}

void* task2(void* arg)
{	
	while(1)
	{
		pthread_mutex_lock(&m);
		pthread_cond_wait(&d,&m);
		b-=5;
		printf("顾客买了5个橘子,还剩%d个橘子\n",b);
		sleep(1);
		pthread_mutex_unlock(&m);
	}

}

int main(int argc, const char *argv[])
{
	srand(time(0));
	pthread_cond_init(&c,0);
	pthread_cond_init(&d,0);
	pthread_mutex_init(&m,0);

	pthread_t id1,id2;
	pthread_create(&id1,0,task1,0);
	pthread_create(&id2,0,task2,0);

	pthread_detach(id1);

	int i;
	while(1)
	{
		int i=rand()%2;
		pthread_mutex_lock(&m);
		sec++;
		if(0==i)
		{
			a++;
			printf("有%d个苹果\n",a);
			if(a>=3)
			{
				pthread_cond_broadcast(&c);
			}
			else
			{
				printf("不满足客服购买需求\n");
			}
		}
		else
		{	
			b+=2;
			printf("有%d个橘子\n",b);
			if(b>=5&&sec%2==0)
			{
				pthread_cond_broadcast(&d);
			}
			else
			{
				printf("不满足客服购买需求\n");
			}
		}
		pthread_mutex_unlock(&m);
		sleep(1);

	}

	return 0;
}

time函数

原型:time_t time(time_t *tloc);
调用形式:
1:  time_t tim = time(0)
2:  time_t tim;
    time(&tim);
    
功能描述:
    time会返回从1970年0:0:0 到调用time函数的时候,所经过的秒数
    如果参数 tloc 不是 NULL,则返回时会被同步的保存到 tloc指向的内存中

localtime函数

原型:struct tm *localtime(const time_t *timep);
调用形式:
    time_t tim = time(0)
    struct tm* lt = localtime(&tim)
    
功能描述:
    将从1970.1.1 0:0:0 到现在经过的秒数,传入localtime函数里面,该函数会自动的把这个时间戳转换成当前的年月日,时分秒 等数据,这些数据会以返回值的形式返回
    struct tm {
        int tm_sec;    /* Seconds (0-60) */
        int tm_min;    /* Minutes (0-59) */
        int tm_hour;   /* Hours (0-23) */
        int tm_mday;   /* Day of the month (1-31) */
        int tm_mon;    /* Month (0-11) */ 1月份是0,12月份是11
        int tm_year;   /* Year - 1900 */ 计算出来的年份,是从1900年开始算的,如果今年是2000年,那么 tm_year的值就是 100
        int tm_wday;   /* Day of the week (0-6, Sunday = 0) */
        int tm_yday;   /* Day in the year (0-365, 1 Jan = 0) */
        int tm_isdst;  /* Daylight saving time */
    };

练习:

编写代码验证递归锁和错误检查锁

#include <stdio.h>
#include <string.h>
#include <stdlib.h>	
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>

typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;

pthread_mutex_t ma;
pthread_mutex_t mb;
int count=-1;

/*
void* task(void* arg)
{
	char b;
	scanf("%c",&b);
	if(b==' ')
	{
		pthread_mutex_unlock(&ma);
	}
}
*/

int main(int argc, const char *argv[])
{
	pthread_mutexattr_t attr,attr1;
	pthread_mutexattr_init (&attr);
	pthread_mutexattr_init (&attr1);
	pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE_NP);
	pthread_mutexattr_settype(&attr1,PTHREAD_MUTEX_ERRORCHECK_NP);
	pthread_mutex_init(&ma,&attr);                              //创建递归锁
	pthread_mutex_init(&mb,&attr1);                             //创建错误信息锁
	
	pthread_t id;
	pthread_create(&id,0,task,0);
	pthread_detach(id);

	//递归锁
	while(1)
	{
		count++;
		printf("lock次数=%d\n",count);
		int a=pthread_mutex_lock(&ma);
		printf("A\n");
		printf("返回值=%d\n",a);
		sleep(1);
	}

/*
	//错误信息锁
	while(1)
	{
		int a=pthread_mutex_lock(&mb);
		printf("A\n");
		printf("返回值=%d\n",a);
		sleep(1);
	}
*/
	return 0;
}

2个生产者线程

1#每秒生产1个苹果

2#每秒生成2个橘子

2个消费者

1#每秒消费3个苹果

2#每两秒消费5个橘子

#include <stdio.h>
#include <string.h>
#include <stdlib.h>	
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>

typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;

pthread_cond_t c;
pthread_cond_t d;
pthread_mutex_t m;
pthread_mutex_t n;
int a=0;
int b=0;
int sec=0;

void* task0(void* arg)
{	
	while(1)
	{
		pthread_mutex_lock(&n);
		b+=2;
		printf("有%d个橘子\n",b);
		if(b>=5&&sec%2==0)
		{
			pthread_cond_broadcast(&d);
		}
		else
		{
			printf("不满足客服购买需求\n");
		}
		pthread_mutex_unlock(&m);
	}

}

void* task1(void* arg)
{	
	while(1)
	{
		pthread_mutex_lock(&m);
		pthread_cond_wait(&c,&m);
		a-=3;
		printf("顾客买了3个苹果,还剩%d个苹果\n",a);
		pthread_mutex_unlock(&m);
	}

}

void* task2(void* arg)
{	
	while(1)
	{
		pthread_mutex_lock(&n);
		pthread_cond_wait(&d,&n);
		b-=5;
		printf("顾客买了5个橘子,还剩%d个橘子\n",b);
		sleep(1);
		pthread_mutex_unlock(&n);
	}

}

int main(int argc, const char *argv[])
{
	srand(time(0));
	pthread_cond_init(&c,0);
	pthread_cond_init(&d,0);
	pthread_mutex_init(&m,0);
	pthread_mutex_init(&n,0);
	pthread_mutex_lock(&n);

	pthread_t id0,id1,id2;
	pthread_create(&id0,0,task0,0);
	pthread_create(&id1,0,task1,0);
	pthread_create(&id2,0,task2,0);

	pthread_detach(id1);

	int i;
	while(1)
	{
		pthread_mutex_lock(&m);
		sec++;
		printf("%d秒\n",sec);
		a++;
		printf("有%d个苹果\n",a);
		if(a>=3)
		{
			pthread_cond_broadcast(&c);
		}
		else
		{
			printf("不满足客服购买需求\n");
		}

		pthread_mutex_unlock(&n);
		sleep(1);

	}

	return 0;
}

2个生产者线程

1#每秒生产1个苹果

2#每秒生成2个橘子

2个消费者

1#每秒消费3个苹果

2#每两秒消费5个橘子

由于仓库有限,生产了橘子之后就不能生成苹果,反之一样。

由于仓库有限,仓库最多存放10个苹果,或者最多20个橘子

#include <stdio.h>
#include <string.h>
#include <stdlib.h>	
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>

typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;

pthread_cond_t c;
pthread_cond_t d;
pthread_cond_t e;
pthread_cond_t f;

pthread_mutex_t m;
pthread_mutex_t n;
pthread_mutex_t i;

int a=0;
int b=0;
int sec=0;
int k=0;
int idex;

void* task(void*arg)
{	
	while(1)
	{
		pthread_mutex_lock(&m);
		pthread_cond_wait(&f,&m);
		sec++;
		printf("第%d秒生产苹果\n",sec);
		if(a<10)
		{
			a++;
		}
		printf("有%d个苹果\n",a);
		if(a>=3)
		{
			pthread_cond_broadcast(&c);
		}
		else
		{
			printf("不满足客服购买需求\n");
		}
		pthread_mutex_unlock(&m);
		//pthread_mutex_unlock(&i);
		sleep(1);
	}
}

void* task0(void* arg)
{	
	while(1)
	{
		pthread_mutex_lock(&n);
		pthread_cond_wait(&e,&n);      //询问是否生产苹果
		sec++;
		printf("第%d秒生产橘子\n",sec);
		if(b<20)
		{
			b+=2;
		}
		printf("有%d个橘子\n",b);
		if(b>=5&&sec%2==0)
		{
			pthread_cond_broadcast(&d);
		}
		else
		{
			printf("不满足客服购买需求\n");
		}	
		pthread_mutex_unlock(&n);
		//pthread_mutex_unlock(&i);
		sleep(1);
	}

}

void* task1(void* arg)
{	
	while(1)
	{
		pthread_mutex_lock(&m);
		pthread_cond_wait(&c,&m);
		a-=3;
		printf("顾客买了3个苹果,还剩%d个苹果\n",a);	
		k=a;	
		if(0==k)
		{
			idex=rand()%2;                   //判断生产苹果还是生产橘子(0生产苹果,1生产橘子)
			printf("idex=%d\n",idex);
			pthread_mutex_unlock(&i);
		}
		else
		{
			pthread_mutex_unlock(&m);
		}
		sleep(1);
	}

}

void* task2(void* arg)
{	
	while(1)
	{
		pthread_mutex_lock(&n);
		pthread_cond_wait(&d,&n);
		b-=5;
		printf("顾客买了5个橘子,还剩%d个橘子\n",b);	
		k=b;
		if(0==k)
		{
			idex=rand()%2;                   //判断生产苹果还是生产橘子(0生产苹果,1生产橘子)
			printf("idex=%d\n",idex);
			pthread_mutex_unlock(&i);
		}
		else
		{
			pthread_mutex_unlock(&n);
		}
		sleep(1);	
	}

}

int main(int argc, const char *argv[])
{
	srand(time(0));

	pthread_cond_init(&c,0);
	pthread_cond_init(&d,0);
	pthread_cond_init(&e,0);
	pthread_cond_init(&f,0);
	pthread_mutex_init(&m,0);
	pthread_mutex_init(&n,0);	
	pthread_mutex_init(&i,0);	




	pthread_t id,id0,id1,id2;
	pthread_create(&id,0,task,0);
	pthread_create(&id0,0,task0,0);
	pthread_create(&id1,0,task1,0);
	pthread_create(&id2,0,task2,0);
	pthread_detach(id);
	pthread_detach(id0);
	pthread_detach(id1);
	pthread_detach(id2);


	idex=rand()%2;                   //判断生产苹果还是生产橘子(0生产苹果,1生产橘子)
	printf("idex初始值=%d\n",idex);
	while(1)
	{		

		pthread_mutex_trylock(&i);
		if(0==idex && b==0)
		{
			pthread_mutex_trylock(&n);
			pthread_cond_broadcast(&f);
			pthread_mutex_unlock(&m);

		}
		else if(1==idex && a==0)
		{
			pthread_mutex_trylock(&m);
			pthread_cond_broadcast(&e);
			pthread_mutex_unlock(&n);
		}
	}



	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值