1、pthread_mutex_t实现进程锁
- 创建进程:fork
- 内存映射区:mmap
- 创建互斥锁:pthread_mutex_init
- 创建互斥锁属性:pthread_mutexattr_init
示例代码
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
// 进程共享数据模型
struct model{
int num;
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
};
int main(){
int length = sizeof(struct model);
/*
int fd = open("temp.txt", O_CREAT | O_RDWR, 0664);
if (fd < 0){
perror("open error:");
exit(1);
}
int ret = ftruncate(fd, length);
if (ret < 0){
perror("ftruncate error");
exit(1);
}
*/
// 创建共享数据(内存映射)
struct model *m = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (m == MAP_FAILED){
perror("mmap error:");
exit(1);
}
memset(m, 0, length);
// 初始化mutex及mutexattr
pthread_mutexattr_init(&m->attr);
// mutex默认状态为线程互斥,通过attr设置为进程互斥
pthread_mutexattr_setpshared(&m->attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&m->mutex, &m->attr);
pthread_mutexattr_destroy(&m->attr);
// 生产随机数种子
srand(time(NULL));
// 创建新进程
pid_t pid = fork();
if (pid < 0){
perror("fork error:");
exit(1);
}else if (pid == 0){
// 父进程
int i = 10;
while(i--){
pthread_mutex_lock(&m->mutex);
m->num += 1;
printf("parent ---- %d\n", m->num);
pthread_mutex_unlock(&m->mutex);
usleep(rand()%500000);
}
// 回收子进程、互斥锁、内存映射
wait(NULL);
pthread_mutex_destroy(&m->mutex);
munmap(m, length);
}else{ // 子进程
int i = 10;
while(i--){
pthread_mutex_lock(&m->mutex);
m->num += 2;
printf("child ---- %d\n", m->num);
pthread_mutex_unlock(&m->mutex);
usleep(rand()%500000);
}
}
return 0;
}
执行结果
parallels@ubuntu:~/Linux/process$ ./mutex.out
child ---- 2
parent ---- 3
parent ---- 4
child ---- 6
child ---- 8
parent ---- 9
child ---- 11
parent ---- 12
parent ---- 13
child ---- 15
child ---- 17
parent ---- 18
child ---- 20
parent ---- 21
child ---- 23
parent ---- 24
child ---- 26
parent ---- 27
child ---- 29
parent ---- 30
parallels@ubuntu:~/Linux/process$
2、fcntl实现文件锁
- F_SETLK:设置文件锁(trylock)
- F_SETLKW:设置文件锁(lock)W->wait
- F_GETLK:获取文件锁
int fcntl(int fd, int cmd, ... /* arg */ );
F_SETLK, F_SETLKW, and F_GETLK are used to acquire, release, and test for the existence of record locks (also known as byte-range, file-segment, or
file-region locks). The third argument, lock, is a pointer to a structure that has at least the following fields (in unspecified order).
struct flock {
...
short l_type; /* Type of lock: F_RDLCK,
F_WRLCK, F_UNLCK */
short l_whence; /* How to interpret l_start:
SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start; /* Starting offset for lock */
off_t l_len; /* Number of bytes to lock */
pid_t l_pid; /* PID of process blocking our lock
(set by F_GETLK and F_OFD_GETLK) */
...
};
示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char* argv[]){
// 要求传入需要加锁的文件路径
if (argc < 2){
printf("e.g: ./a.out filename\n");
exit(1);
}
const char* filename = argv[1];
// 初始化文件锁结构体
struct flock lock;
//lock.l_type = F_RDLCK; // 加锁类型(读或写)
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET; // 加锁位置(当前位置、起始位置、末尾位置)
lock.l_start = 0; // 开始位置偏移量
lock.l_len = 0; // 加锁长度(单位字节),0则全部加锁
int fd = open(filename, O_RDWR);
if (fd < 0){
perror("open error");
exit(1);
}
// 设置文件锁:SETLKW,阻塞形式设置(加锁还是解锁取决于结构体lock中的值)
fcntl(fd, F_SETLKW, &lock);
printf("file is locked with 'F_RDLCK'\n");
sleep(10);
// 修改结构体参数
lock.l_type = F_UNLCK;
// 设置文件锁(解锁)
fcntl(fd, F_SETLKW, &lock);
printf("file is unlock...\n”);
// 关闭文件
close(fd);
return 0;
}
执行结果:
* 在锁为读的情况下,多进程可以对单个文件同时操作;
* 在锁为写的情况下,多进程会被阻塞等待,只有上一个进程解锁后,下一个才能进行加锁