Skip to content

Instantly share code, notes, and snippets.

@jorben
Last active June 8, 2022 12:26
Show Gist options
  • Save jorben/c56e85c96845a866f95e to your computer and use it in GitHub Desktop.
Save jorben/c56e85c96845a866f95e to your computer and use it in GitHub Desktop.
mmap写文件,多进程
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/sem.h>
#include <fcntl.h>
#define DFN_SEM_KEY 0xA001FFFF
typedef enum
{
false,
true
}bool;
static int g_sem_id = -1;
int io(char* filename, char* buf, size_t len);
uint64_t getCurrTimeUs()
{
struct timeval stTime;
gettimeofday(&stTime,NULL);
long long tmpTime = stTime.tv_sec * 1000000ull;
return tmpTime + stTime.tv_usec;
}
static bool s_wait_sem();
static void s_unlock_sem();
int main(int argc, char** argv)
{
size_t i;
uint64_t t_begin = getCurrTimeUs();
char* chFileName = "./log_mmap.txt";
for(i=0; i<30; i++)
{
pid_t pid = fork();
if(0 == pid)
{
size_t j;
char tmp[32], buf[64];
int son_pid = getpid();
memset(tmp, '\0', sizeof(tmp));
snprintf(tmp, sizeof(tmp), "%s_%u", chFileName, son_pid);
uint64_t t_son_begin = getCurrTimeUs();
for(j=0; j<10000; j++)
{
memset(buf, '\0', sizeof(buf));
snprintf(buf, sizeof(buf), "pid: %u, i:%zu, j:%zu\n", son_pid, i, j);
#if defined _UN_LOCK_
// 按进程分文件 无锁写入
io(tmp, buf, strlen(buf));
// io(chFileName, buf, strlen(buf));
#else
// 多进程进程写入 带锁
io(chFileName, buf, strlen(buf));
#endif
// usleep(1000);
}
printf("son:%u time cost(us):%lu\n", son_pid, getCurrTimeUs() - t_son_begin);
exit(0);
}
}
printf("time cost(us):%lu\n", getCurrTimeUs() - t_begin);
return 0;
}
int io(char* filename, char* buf, size_t len)
{
int pos = 0;
int fd = open(filename, O_CREAT | O_RDWR, 00600);
if (-1 == fd)
{
perror("open error");
return -1;
}
if(s_wait_sem())
{
// 获取锁 后进行占位
pos = lseek(fd, 0, SEEK_END);
lseek(fd, len-1, SEEK_END);
write(fd, "", 1);
s_unlock_sem();
}
int dwMapLen = len + pos;
char * p_map = (char*)mmap(NULL, dwMapLen, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if(p_map == MAP_FAILED)
{
close(fd);
perror("mmap error");
return -1;
}
close(fd);
memcpy(p_map+pos, buf, len);
munmap(p_map, dwMapLen);
return 0;
}
static void s_unlock_sem()
{
if(0 > g_sem_id)
return ;
struct sembuf lock;
lock.sem_num = 0;
lock.sem_op = 1;
lock.sem_flg = SEM_UNDO; // 进程退出(正常或非正常)时可以自动释放锁
semop(g_sem_id, &lock, 1);
return ;
}
// 创建/打开 只允许一个进程进行P操作的信号量,并等待它
static bool s_wait_sem()
{
#if defined _UN_LOCK_
return true;
#endif
g_sem_id = semget(DFN_SEM_KEY, 1, IPC_CREAT|IPC_EXCL|0666);
if (g_sem_id >= 0)
{
// 计算机重启后,首次启动进程
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
} arg;
arg.val = 1; // 只允许一个进程P操作
int n = semctl(g_sem_id, 0, SETVAL, arg);
if (n != 0)
{
semctl(g_sem_id, 0, IPC_RMID);
return false;
}
}
else
{
// 可能已经存在,尝试打开
g_sem_id = semget(DFN_SEM_KEY, 1, IPC_CREAT|0666);
if (g_sem_id < 0)
{
return false;
}
}
struct sembuf lock;
lock.sem_num = 0;
lock.sem_op = -1;
lock.sem_flg = SEM_UNDO; // 进程退出(正常或非正常)时可以自动释放锁
int n = semop(g_sem_id, &lock, 1); // 只有一个进程能够获得锁,其他进程会卡在这里等待
if (n != 0)
{
semctl(g_sem_id, 0, IPC_RMID);
return false;
}
return true;
}
@jorben
Copy link
Author

jorben commented Dec 5, 2015

// 单文件多进程写入(带锁)
// gcc -o log_mmap logmmap.c
// 多进程分文件写入(无锁)
// gcc -D _UN_LOCK_ -o log_mmap_unlock log_mmap.c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment