前面已经介绍完了线程同步的方式,现在来介绍一下进程的同步方式
一.mutex【互斥量】
大家有一个错觉就是 以为 mutex只能用户线程间同步,其实不然mutex 其实可以用于进程间同步,在pthread_mutex_init之前,要修改他的 mutex属性就可以了
mutex属性修改的函数主要有以下几个
主要应用函数:
pthread_mutexattr_t mattr类型:
用于定义mutex,锁的【属性】初始化一个mutex.属性对象
pthread_mutexattr_init函数:
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
pthread_mutexattr_destroy函数:
销毁mutex,属性对象(而非销毁锁)
int pthread_mutexattr_destroy(pthread_mutexattr_t*attr);
pthread_mutexattr_setpshared,函数:
修改mutex属性。
int pthread_mutexattr. setpshared(pthread_mutexattr t *attr, int pshared);
#include <iostream>
#include <pthread.h>
#include <sys/mman.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/wait.h>
using namespace std;
typedef int ELEMTPEY;
struct data_t
{
ELEMTPEY elem;
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
};
int
main(int argc, char*argv[])
{
struct data_t *object;
pid_t pid;
// 因为是 血缘关系进程间 共享 我用的匿名映射
object = (struct data_t*)mmap(NULL, sizeof(struct data_t),
PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
if(object == MAP_FAILED){
perror("mmap error");
exit(1);
}
memset(object, 0, sizeof(struct data_t));
object->elem = 0;
pthread_mutexattr_init(&object->attr);
pthread_mutexattr_setpshared(&object->attr, PTHREAD_PROCESS_SHARED); // 设置属性成进程间互斥量
pthread_mutex_init(&object->mutex, &object->attr);
srand(time(NULL));
pid = fork();
if(pid < 0){
perror("fork error");
munmap(object, sizeof(struct data_t)); // 如果创建失败 取消内存映射
exit(1);
}else if(pid > 0){ // son read + write
int i=5;
while(i--){
pthread_mutex_lock(&object->mutex);
printf("I am child \n");
object->elem += 2;
printf("the elem :%d \n", object->elem);
pthread_mutex_unlock(&object->mutex);
sleep(rand()%2+1);
}
}else{ // parent write
int i=5;
while(i--){
pthread_mutex_lock(&object->mutex);
printf("I am parent\n");
object->elem++;
printf("the elem :%d \n", object->elem);
pthread_mutex_unlock(&object->mutex);
sleep(rand()%2+1);
}
wait(NULL);
pthread_mutexattr_destroy(&object->attr);
pthread_mutex_destroy(&object->mutex);
munmap(object, sizeof(struct data_t));
}
return 0;
}
二.文件锁
借助fcntl函数来实现锁机制,操作文件的进程没有获取锁时,可以打开但无法执行read,write操作。
fcntl函数:获取,设置文件访问控制属性。
int fcntl(int fd, int cmd, .../* arg*/ );
参2:
F_SETLK(struct flock *)设置文件锁〈trylock)
F_SETLKW (struct flock*)设置文件锁(lock)w --> waitF_GETLK(struct flock *)获取文件锁
参3:
struct flock {
…
short l_type; 锁的类型:F_RDLCK . F_WRLCK . F_UNLCK
short l_whence; 偏移位置: SEEK_SET、SEEK_CUR、SEEK_END
off_t l_start; 起始偏移:1000
off_t l_len; 长度:0表示整个文件加锁
pid_t l pid; 持有该锁的进程ID:(F_GETLK only)
.…
};
文件锁Demo_(线程没有文件锁因为共享文件描述符)
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
using namespace std;
void
sys_err(const char* strerr)
{
perror(strerr);
exit(1);
}
int
main(int argc, char*argv[])
{
int fd;
struct flock file_lock;
if(argc != 2)
sys_err("./a.out filename");
if((fd = open(argv[1], O_RDWR)) < 0)
sys_err("open file err");
// file_lock.l_type = F_RDLCK;
file_lock.l_type = F_WRLCK;
file_lock.l_whence = SEEK_SET;
file_lock.l_start = 0;
file_lock.l_len = 0;
char buf[56];
fcntl(fd, F_SETLKW, &file_lock);
printf("get lock\n");
int size = read(fd, buf, sizeof(buf));
buf[size] = '\0';
printf("buf:%s \n", buf);
sleep(20);
file_lock.l_type = F_UNLCK;
fcntl(fd, F_SETLKW, &file_lock);
printf("un lock\n");
close(fd);
return 0;
}
L_type = F_WRLCK(独享)
L_type = F_RDLCK(共享(可以多个进程访同一个文件))