一.文件锁
//获取锁,如果已经被占用立即返回,errno被设置为EAGAIN
int try_lock_fd(int fd)
{
struct flock fl;
fl.l_start = 0;
fl.l_len = 0;
fl.l_pid = 0;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
//如果锁已经被占用,errno会被设置为 EAGAIN
return fcntl(fd, F_SETLK, &fl);
}
//获取锁,如果已经被占用则等待
int lock_fd(int fd)
{
struct flock fl;
fl.l_start = 0;
fl.l_len = 0;
fl.l_pid = 0;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
return fcntl(fd, F_SETLKW, &fl);
}
//释放文件锁即返回,errno被设置为EAGAIN
int unlock_fd(int fd)
{
struct flock fl;
fl.l_start = 0;
fl.l_len = 0;
fl.l_pid = 0;
fl.l_type = F_UNLCK;
fl.l_whence = SEEK_SET;
return fcntl(fd, F_SETLK, &fl);
}
二.共享内存+内存信号量(又称无名信号量)
下面是一个简单的测试程序:
#include<semaphore.h>
#include<stdio.h>
#include<errno.h>
#include</usr/include/sys/mman.h>
sem_t* psem = NULL;
int main()
{
pid_t pid;
psem = mmap(NULL, sizeof(sem_t),
PROT_READ|PROT_WRITE,
MAP_ANON|MAP_SHARED, -1, 0);
if(MAP_FAILED == psem)
{
printf("mmap failed !\n");
return -1;
}
if(-1== sem_init(psem, 1, 0))
{
printf("sem_init err:%d\n", errno);
}
pid = fork();
if(pid < 0)
{
printf("fork err:%d", errno);
}
if(0 == pid)
{
sleep(5);
if( -1 == sem_post(psem))
{
printf("post sem ! errno:%d\n", errno);
}
else
}
else
{
printf("post sem secceed !\n");
}
}
if(pid > 0)
{
if(-1 == sem_wait(psem))
{
printf("wait sem errno:%d\n", errno);
}
else
{
printf("wait sem succeed !\n");
}
}
printf("process exit\n");
return 0;
}
三.共享内存+锁
共享内存+互斥锁或者读写锁或者原子锁,都可以实现进程间互斥
以原子锁为例;
#include <stdio.h>
#include<unistd.h>
#include</usr/include/sys/mman.h>
inline int atom_cmp_set(unsigned long *mem,unsigned long newval,unsigned long oldval)
{
unsigned char res;
__asm __volatile ("lock;"
"cmpxchg %3, %1;"
"sete %0;"
: "=a" (res)
: "m" (*mem), "a" (oldval), "r" (newval)
: "cc", "memory" );
return (int) res;
}
int main()
{
int ret = 0;
pid_t pid = 0;
unsigned long* atom_val = mmap(NULL, sizeof(unsigned long),
PROT_READ|PROT_WRITE,
MAP_ANON|MAP_SHARED, -1, 0);
if(MAP_FAILED == atom_val)
{
printf("err in mmap !");
return -1;
}
*atom_val = 0;
if((pid = fork()) < 0)
{
printf("fork err !\n");
return 0;
}
ret = atom_cmp_set(atom_val, 1, 0);
if(1 == ret)
{
printf("in %s process atom_cmp_set secceed atom_val:%d\n", pid == 0 ? "child":"parent", *atom_val);
}
else
{
printf("in %s process atom_cmp_set failed atom_val:%d \n", pid == 0 ? "child":"parent", *atom_val);
}
return 0;
}
输出:
in parent process atom_cmp_set secceed atom_val:1
in child process atom_cmp_set failed atom_val:1