我们知道,多线程可以用多线程互斥量pthread_mutex_t实现线程之间上锁,那么多进程之间如何共享锁呢?
1. 文件锁实现多进程锁
由于文件锁是存放到位于内存的系统文件表中, 所有进程/线程可通过系统访问。如果不同进程使用同一文件锁(写锁/排他锁),当取得文件锁时,进程可继续执行;如果没有取得锁,则阻塞等待。而唯一标识该文件的是文件路径,因此,可以通过一个共同的文件路径,来实现多进程锁机制。
参见文件锁的本质核心和原理 | CSDN
关键点:
1)创建/打开一个唯一路径的文件;
2)P操作,取得文件的写锁(排他锁);V操作,释放文件的锁;
static struct flock lock_it; /* 用于加锁的flock对象 */
static struct unlock_it; /* 用于解锁的flock对象 */
static int lock_fd = -1;
void
my_lock_init(char *pathname)
{
char lock_file[1024]; /* 存放文件名的临时缓存 */
/* 由于mkstemp会修改参数的最后6个字符,为避免pathname是字符串常量,需要将字符串从pathname copy到临时缓存lock_file中,然后作为创建唯一临时文件的参数 */
strncpy(lock_file, pathname, sizeof(lock_file));
lock_fd = mkstemp(lock_file); /* 创建唯一的临时文件并打开 */
unlink(lock_file); /* 删除指定文件名的文件,如果有进程打开了该文件,会在进程结束后所有指向该文件的描述符都关闭后删除文件。这样可以确保即使程序崩溃,临时文件也会完全消失 */
/* 设置flock对象的写锁属性 */
lock_it.l_type = F_WRLCK;
lock_it.l_whence = SEEK_SET;
lock_it.l_start = 0;
lock_it.l_len = 0;
/* 设置flock对象的解锁属性 */
unlock_it.l_type = F_UNLCK;
unlock_it.l_whence = SEEK_SET;
unlock_it.l_start = 0;
unlock_it.l_len = 0;
}
void
my_lock_wait()
{
int rc;
/* 取得写锁,如果阻塞等待时被中断唤醒,则继续恢复阻塞等待锁资源 */
whilel ((rc = fcntl(lock_fd, F_SETLKW, &lock_it)) < 0) {
if (errno == EINTR) continue;
else err_sys("my_lock_wait fcntl error"); /* 如果没有调用my_lock_init就直接调用fcntl,将会失败 */
}
}
void
my_lock_release()
{
if (fcntl(lock_fd, F_SETLKW, &unlock_it) < 0)
err_sys("my_lock_release fcntl error");
}
2. 多线程锁实现多进程锁
多线程之间天然共享内存/变量,而多进程各有自己的进程空间,它们之间是不共享数据的
2个关键步骤
1)互斥锁变量存放到共享内存;
2)设置互斥锁变量的进程共享属性(PTHREAD_PROCESS_SHARED);
static pthread_mutex_t *mptr; /* 互斥锁变量指针,互斥锁变量存放到共享内存 */
/**
* 多进程互斥锁变量初始化
*/
void
my_lock_init()
{
int fd;
pthread_mutexattr_t mattr;
/* 新建共享内存区域,但不映射到实际的普通文件 */
fd = open("/dev/zero", O_RDWR, 0);
if (fd < 0) err_sys("open error");
mptr = mmap(0, sizeof(pthread_mutex_t), PORT_READ | PORT_WRITE, MAP_SHARED, fd, 0);
if (mptr == MAP_FAILED) err_sys("mmap");
if (close(fd)) err_sys("close error");
pthread_mutexattr_init(&mattr);
pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
phtread_mutex_init(mptr, &mattr);
}
/**
* 加锁
*/
void
my_lock_wait()
{
pthread_mutex_lock(mptr);
}
/**
* 解锁
*/
void
my_lock_release()
{
pthread_mutex_unlock(mptr);
}