Linux高级 2019-6-1下午

1.进程互斥锁

1.1 与线程锁类型相同,也是 pthread_mutex_t 类型

1.2 修改线程锁属性,将其更改为进程锁

1.3 原子锁相关函数

  • pthread_mutexattr_t : 原子锁属性类型
  • pthread_mutexattr_inti(pthread_mutexattr_t*) : 初始化原子锁属性
  • pthread_mutexattr_destroy(pthread_mutexattr_t*) : 销毁原子锁属性
  • pthread_mutexattr_setpshared(pthread_mutexattr_t*, int pshared) : 更改原子锁属性

1.4 通过修改线程锁属性,使用进程锁完成父子进程对共享资源操作

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

#define COUNT 5000

typedef struct
{
	int n_code;
	pthread_mutex_t process_lock;
}ProData;

int main()
{
	int fd;

	// 创建线程锁属性变量
	pthread_mutexattr_t attr;

	ProData* p_pro;

	fd = open("ProcessFile", O_RDWR|O_CREAT, 0664);
	ftruncate(fd, sizeof(ProData));
	p_pro = mmap(NULL, sizeof(ProData), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	bzero(p_pro, sizeof(ProData));

	// 修改属性
	pthread_mutexattr_init(&attr);
	pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);

	// 用户自定义互斥锁属性初始化互斥锁
	pthread_mutex_init(&(p_pro->process_lock), &attr);

	// 销毁线程锁属性
	pthread_mutexattr_destroy(&attr);

	pid_t pid;
	pid = fork();
	if(pid > 0)
	{
		for(int i=0; i<COUNT; i++)
		{
			pthread_mutex_lock(&(p_pro->process_lock));
			printf("Parent PID:%d\t++code:%d\n", getpid(), ++(p_pro->n_code));
			pthread_mutex_unlock(&(p_pro->process_lock));
		}
	}
	else if(pid == 0)
	{
		for(int i=0; i<COUNT; i++)
		{
			pthread_mutex_lock(&(p_pro->process_lock));
			printf("Child PID:%d\t++code:%d\n", getpid(), ++(p_pro->n_code));
			pthread_mutex_unlock(&(p_pro->process_lock));
		}
		exit(0);
	}
	else
	{
		perror("fork error");
		exit(0);
	}

	// 回收子进程
	pid_t wpid;
	wpid = wait(NULL);

	printf("Wait PID:%d\n", wpid);

	return 0;
}

2.文件锁

2.1 Linux中使用文件锁时一般可采用 lockf 或 fcntl 函数

2.2 lockf 为文件建议锁, fcntl 为可选择建议锁或强制锁

2.3 例子

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

void sys_err(char *str)
{
	perror(str);
	exit(1);
}

int main(int argc, char *argv[])
{
	int fd;
	struct flock f_lock;
	if (argc < 2) {
		printf("./ts filename\n");
		exit(1);
	}
	if ((fd = open(argv[1], O_RDWR)) < 0)
		sys_err("open");
	//f_lock.l_type = F_WRLCK;
	f_lock.l_type = F_RDLCK;
	f_lock.l_whence = SEEK_SET;
	f_lock.l_start = 0;
	f_lock.l_len = 0; //0表示整个文件加锁
	fcntl(fd, F_SETLKW, &f_lock);
	printf("get flock\n");
	sleep(10);
	f_lock.l_type = F_UNLCK;
	fcntl(fd, F_SETLKW, &f_lock);
	printf("un flock\n");
	close(fd);
	return 0;
}
  • 目前没懂该程序的作用

3.信号量

3.1 信号量分为一元灯、多元灯

3.2 一元灯创建过程

  • 1.定义信号量类型
  • 2.初始化信号量(设置灯值,灯值为1即为一元信号灯),信号量创建出的临界区通过灯值访问,只有灯值大于0时允许进入临界区,进入后灯值减1,使用临界区代码,使用完后将灯值加1;

3.3 使用信号量的一元灯与互斥锁没有区别(都是锁资源的)

3.4 多元灯(灯值大于1):用来锁流程业务

3.5 信号量函数

  • 有名信号量
  • 无名信号量(一般使用无名信号量)

4.死锁

4.1 概念

  • 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象死锁。
  • 简述:死锁是指在一组进程中的各个进程均占有不会释放的资源,但因互相申请被其他进程所站用不会释放的资源而处于的一种永久等待状态。

4.2 使用线程同步技术要尽力避免死锁问题

4.3 死锁问题就是指多线程访问数据混乱,例如两个线程相互申请他人已占用的资源,导致操作阻塞

4.4 死锁的必要条件:

  • 互斥条件(Mutual exclusion):资源不能被共享,只能由一个进程使用。
  • 请求与保持条件(Hold and wait):已经得到资源的进程可以再次申请新的资源。
  • 非剥夺条件(No pre-emption):已经分配的资源不能从相应的进程中被强制地剥夺。
  • 循环等待条件(Circular wait):系统中若干进程组成环路,该环路中每个进程都在等待相邻进程正占用的资源。

4.5 解决死锁的方式:

  • 1.服务者模式:每次使用全局变量之前都进行询问,可以使用则使用,否则继续等待;
  • 2.银行家模式:判断资源使用的风险,风险较大则拒绝使用,否则可以使用。

5.无锁编程与有锁编程的区别

  • 速度最快的是什么都没有的编程(基础编程);其次是无锁编程;最后是有锁编程(加锁解锁会消耗大量的时间资源);
  • 无锁编程无法再次进行优化,有锁编程可以进行再优化(减少锁的使用频率);
  • 无锁编程简单,易于实现,但是无法再优化。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值