file lock and thread sync operations (I)

多线程文件锁机制
本文探讨了多线程环境下使用flock进行文件锁管理的方法,包括不同线程间文件写入的操作顺序及其实现细节,对比了flock与其他锁机制的区别。
第一点,多线程,每个线程都open flock write,不必explicitly sync threads(mutex、rdlock等),每个线程操作锁的顺序内部有序,并且,如果文件以append方式打开,文件写入不会混乱,如果以trunc方式打开,则文件内容可能混乱(write offset的原因,引起覆盖)。
第二点,flock,是进程层面的锁(第一点可印证),同时,这个锁与kernel维护的open file table关联。可联想下process table -- open file table -- vnode/inode table。
第三点,只主线程中open,然后把fd传给各子线程,各线程通过explicit thread sync来操作共享的fd。这个方法也可行。与flock相比,哪个更好,待确认。

第四点,flock vs. lockf vs. flockfile。


#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/file.h>


#ifndef MYNB
# ifdef LOCK_NB
#  undef LOCK_NB
# endif
#define LOCK_NB 0
#endif


#ifdef __cplusplus
extern "C" {
#endif


#if 0
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
#endif

void *thr_fn(void *data)
{
    pthread_t tid = pthread_self();
    const char *fn = (const char *)data;
    int fd, len;
    char buf[32];

    fprintf(stderr, "in thr... %lu\n", tid);

    // fd = open(fn, O_RDWR | O_CREAT | O_APPEND, 0666);
    fd = open(fn, O_RDWR | O_CREAT, 0666);

    if (fd == -1) {
        char errbuf[64];
        strerror_r(errno, errbuf, sizeof(errbuf));
        fprintf(stderr, "in thr %lu: %s\n", tid, errbuf);
        return (void *)-1;
    }

    fprintf(stderr, "in thr %lu fd: %d\n", tid, fd);

    if (flock(fd, LOCK_EX | LOCK_NB) == -1) {
        char errbuf[64];
        close(fd);
        strerror_r(errno, errbuf, sizeof(errbuf));
        fprintf(stderr, "in thr %lu: %s\n", tid, errbuf);
        return (void *)-1;
    } else {
        fprintf(stderr, "in thr %lu: flock OK\n", tid);
    }

    len = snprintf(buf, sizeof(buf), "%lu\n", tid);
    fprintf(stderr, "in thr %lu, to be written: %d\n", tid, len);

#if 0
    pthread_mutex_lock(&mutex);
#endif

    len = write(fd, buf, len);
#if 0
    fsync(fd);
#endif

#if 0
    pthread_mutex_unlock(&mutex);
#endif

    fprintf(stderr, "in thr %lu, written: %d\n", tid, len);

    if (flock(fd, LOCK_UN | LOCK_NB) == -1) {
        char errbuf[64];
        close(fd);
        strerror_r(errno, errbuf, sizeof(errbuf));
        fprintf(stderr, "in thr %lu: %s\n", tid, errbuf);
        return (void *)-1;
    } else {
        fprintf(stderr, "in thr %lu: flock un\n", tid);
    }

    close(fd);

    fprintf(stderr, "leaving thr... %lu\n", tid);

    return (void *)0;
}

int main(void)
{
    const char *fn = "./foo.txt";
    pthread_t tid1, tid2, tid = pthread_self();
    int fd, len;
    char buf[32];

    pthread_create(&tid1, NULL, thr_fn, (void *)fn);

    fprintf(stderr, "main %lu\n", tid);

#if 0
    sleep(2);
#endif

    // fd = open(fn, O_RDWR | O_CREAT | O_APPEND, 0666);
    fd = open(fn, O_RDWR | O_CREAT, 0666);

    if (fd == -1) {
        char errbuf[64];
        strerror_r(errno, errbuf, sizeof(errbuf));
        fprintf(stderr, "main: %s\n", errbuf);
    }

    fprintf(stderr, "main fd: %d\n", fd);

    if (flock(fd, LOCK_EX | LOCK_NB) == -1) {
        char errbuf[64];
        close(fd);
        strerror_r(errno, errbuf, sizeof(errbuf));
        fprintf(stderr, "main: %s\n", errbuf);
    } else {
        fprintf(stderr, "main: flock OK\n");
    }

#if 0
    sleep(2);
#endif

    pthread_create(&tid2, NULL, thr_fn, (void *)fn);

    len = snprintf(buf, sizeof(buf), "%lu\n", tid);
    fprintf(stderr, "main, to be written: %d\n", len);

#if 0
    pthread_mutex_lock(&mutex);
#endif

    len = write(fd, buf, len);
#if 0
    fsync(fd);
#endif

#if 0
    pthread_mutex_unlock(&mutex);
#endif

    fprintf(stderr, "main, written: %d\n", len);

    if (flock(fd, LOCK_UN | LOCK_NB) == -1) {
        char errbuf[64];
        close(fd);
        strerror_r(errno, errbuf, sizeof(errbuf));
        fprintf(stderr, "main: %s\n", errbuf);
    } else {
        fprintf(stderr, "main: flock un\n");
    }

    close(fd);

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    fprintf(stderr, "leaving main...\n");
    return 0;
}


#ifdef __cplusplus
}
#endif


解释mysql死锁的日志: ===================================== 2025-09-01 09:55:04 0x7f3fbc050700 INNODB MONITOR OUTPUT ===================================== Per second averages calculated from the last 12 seconds ----------------- BACKGROUND THREAD ----------------- srv_master_thread loops: 476498 srv_active, 0 srv_shutdown, 1447826 srv_idle srv_master_thread log flush and writes: 1924324 ---------- SEMAPHORES ---------- OS WAIT ARRAY INFO: reservation count 786321 OS WAIT ARRAY INFO: signal count 926316 RW-shared spins 0, rounds 1718525, OS waits 727495 RW-excl spins 0, rounds 1882762, OS waits 11958 RW-sx spins 79315, rounds 1036013, OS waits 7961 Spin rounds per wait: 1718525.00 RW-shared, 1882762.00 RW-excl, 13.06 RW-sx ------------ TRANSACTIONS ------------ Trx id counter 212854539 Purge done for trx's n:o < 212854539 undo n:o < 0 state: running but idle History list length 7 LIST OF TRANSACTIONS FOR EACH SESSION: ---TRANSACTION 421387126964768, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126963856, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126955648, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126962944, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126952000, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126945616, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126962032, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126961120, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126960208, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126959296, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126957472, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126958384, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126956560, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126954736, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126953824, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126952912, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126950176, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126949264, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126948352, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126946528, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126951088, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 421387126947440, not started 0 lock struct(s), heap size 1136, 0 row lock(s) -------- FILE I/O -------- I/O thread 0 state: waiting for completed aio requests (insert buffer thread) I/O thread 1 state: waiting for completed aio requests (log thread) I/O thread 2 state: waiting for completed aio requests (read thread) I/O thread 3 state: waiting for completed aio requests (read thread) I/O thread 4 state: waiting for completed aio requests (read thread) I/O thread 5 state: waiting for completed aio requests (read thread) I/O thread 6 state: waiting for completed aio requests (write thread) I/O thread 7 state: waiting for completed aio requests (write thread) I/O thread 8 state: waiting for completed aio requests (write thread) I/O thread 9 state: waiting for completed aio requests (write thread) Pending normal aio reads: [0, 0, 0, 0] , aio writes: [0, 0, 0, 0] , ibuf aio reads:, log i/o's:, sync i/o's: Pending flushes (fsync) log: 0; buffer pool: 0 1761764 OS file reads, 6819779 OS file writes, 3690487 OS fsyncs 0.67 reads/s, 16384 avg bytes/read, 6.00 writes/s, 1.92 fsyncs/s ------------------------------------- INSERT BUFFER AND ADAPTIVE HASH INDEX ------------------------------------- Ibuf: size 1, free list len 2679, seg size 2681, 11096 merges merged operations: insert 92451, delete mark 2249405, delete 17526 discarded operations: insert 0, delete mark 0, delete 0 Hash table size 34673, node heap has 158 buffer(s) Hash table size 34673, node heap has 1 buffer(s) Hash table size 34673, node heap has 1 buffer(s) Hash table size 34673, node heap has 237 buffer(s) Hash table size 34673, node heap has 232 buffer(s) Hash table size 34673, node heap has 121 buffer(s) Hash table size 34673, node heap has 134 buffer(s) Hash table size 34673, node heap has 135 buffer(s) 0.17 hash searches/s, 30.83 non-hash searches/s --- LOG --- Log sequence number 215046801169 Log flushed up to 215046801169 Pages flushed up to 215046801169 Last checkpoint at 215046801160 0 pending log flushes, 0 pending chkp writes 2133962 log i/o's done, 1.08 log i/o's/second ---------------------- BUFFER POOL AND MEMORY ---------------------- Total large memory allocated 137428992 Dictionary memory allocated 4344751 Buffer pool size 8191 Free buffers 1024 Database pages 6148 Old database pages 2249 Modified db pages 0 Pending reads 0 Pending writes: LRU 0, flush list 0, single page 0 Pages made young 459823, not young 48387027 0.00 youngs/s, 0.00 non-youngs/s Pages read 1761268, created 56646, written 4245741 0.00 reads/s, 0.00 creates/s, 0.00 writes/s Buffer pool hit rate 994 / 1000, young-making rate 5 / 1000 not 57 / 1000 Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s LRU len: 6148, unzip_LRU len: 0 I/O sum[293]:cur[21], unzip sum[0]:cur[0] -------------- ROW OPERATIONS -------------- 0 queries inside InnoDB, 0 queries in queue 0 read views open inside InnoDB Process ID=1141, Main thread ID=139911780890368, state: sleeping Number of rows inserted 2674988, updated 1754190, deleted 693973, read 330897854 9.67 inserts/s, 0.25 updates/s, 0.00 deletes/s, 80.16 reads/s ---------------------------- END OF INNODB MONITOR OUTPUT ============================
09-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值