【Linux】 数据管理

内存管理

从segmentation fault (core dumped)问题出发:

原因(目前我遇到的):
一个是内存访问越界;
一个是访问空指针。

malloc calloc realloc的区别:

void *malloc(size_t size)
void *calloc(size_t number_of_elements, size_t element_size);
void *realloc(void *existing_memory, size_t new_size);

malloc 和 calloc都是返回一段空间的首地址, 里面的值都被初始化为0;
realloc一般是对calloc和malloc内存进行扩充,一般(如果可以)将会在原来的地址后续添加,否则将在新地址上新辟空间,将原地址的数据拷贝过去。
一般的使用如下:

my_ptr = malloc(BLOCK_SIZE);
...
tmp_ptr = my_ptr;
tmp_ptr = realloc(tmp_ptr, BLOCK_SIZE*2);
if (tmp_ptr != NULL) {
    my_ptr = tmp_ptr;   
}

这里考虑的地方有俩处:
1)realloc 可能返回 NULL
2)realloc成功的话,会自动判断realloc返回的指针是否跟先前的一致,不一致会自动free掉(来自 realloc函数心得

文件锁定

创建文件锁:

文件锁的原理,就是创建文件(建立锁),如果文件已存在(已经有进程创建文件锁) 则返回错误信息。
文件锁的创建, 是通过系统调用open(“lock_file”,O_RDWR|O_CREAT|O_EXCL, 0444)创建的。其中,O_CREAT|O_EXCL 表示如果文件未存在则创建,否则返回错误信息(17),open失败(返回-1).其中0444,表示创建文件的权限rwx(这里应该是-r–r–r–)
这里是例子程序:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>

const char *lock_file = "/tmp/LCK.test2";

int main()
{
    int file_desc;
    int tries = 10;

    while(tries --) {
        file_desc = open(lock_file, O_RDWR|O_CREAT| O_EXCL, 0444);
        if (file_desc == -1) {
            printf("%d - Lock already present\n", getpid());
            printf("Open failed with error %d\n", errno);
            sleep(3);
        } else {
            //这里是临界区
            //***********************
            printf("%d - I have exclusive access\n", getpid());
            sleep(1);
            //***********************
            (void)close(file_desc);
            //此处"删除"文件, 理解为释放锁
            (void)unlink(lock_file);

            sleep(2);
        }
    }
    exit(EXIT_SUCCESS);
}

其中 unlink 的作用是“删除“文件, 这里准确的来说 是删除(硬)链接。linux删除一个文件,是看其硬链接个数, 如果硬链接个数为0, 则该文件被标记为可覆盖(其实文件内容仍然存在,直至新的文件写入覆盖之,毕竟真正的删除是很费事的(每个字节全部替换成0xcc?))

区域锁定

概要:锁定一个文件的某个区域
方式有fcntl(最常用) lockf。注意 由于俩者使用不同的底层实现,所以必须坚决的使用其中一种
函数调用为int fcntl(int fildes, int command, struct flock *flock_structure);

flock 结构包括:
1short l_type
2short l_whence
3)off_t l_start
4)off_t l_len
5)pid_t l_pid

其中l_type取值有F_RDLCK, F_WRLCK, F_UNLCK. 分别为共享锁,独占锁,解锁。(read允许有多个(共享),write只能有一个(独占),并且read时不允许有writer,write时不允许有reader。读者-写者问题)

//读者-写者问题代码
//writer
do{
    wait(writeLock);
    ...
    //write here
    ...
    signal(writeLock);
} while(TRUE);

//reader
do {
    wait(readLock);
    readcount++;
    if (readcount == 1)
        wait(writeLock);
    signal(readLock);
    ...
    //read here
    ...
    wait(readLock);
    readcount--;
    if (readcount == 0)
        signal(writeLock);
    signal(readLock);
} while(TRUE);

其中readLock是保证readcount多线程的安全,而总的来看,reader也是 wait(writeLock) ... signal(writeLock).

回到fcntl(fildes, command, flock_structure)
其中command 有 F_GETLK F_SETLK F_SETLKW.
F_GETLK:
尝试获取锁的信息,一般会返回不为-1的值,而且一般会修改flock_structure,l_pid此时的值是当前获得锁的进程id号,此处flock需要使用的值是type,whence,start,len,pid
F_SETLK:
功能为加锁,如果加锁失败(如对已独占区域加锁,对共享区域加独占锁)函数返回-1.(l_pid 与get不同 此时并不会修改)
F_SETLKW:
功能与上文一致,不同的是,无法得到锁时,将等待。。。只有在获得锁或者接受到信号才返回。

这三种锁,将会随着相关文件描述符fildes的关闭而自动清除。

代码:

//来自 Linux程序设计
lock3.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>

const char *test_file = "/tmp/test_lock";

int main()
{
    int file_desc;
    int byte_count;
    char *byte_to_write = "A";
    struct flock region_1;
    struct flock region_2;
    int res;


    file_desc = open(test_file, O_RDWR | O_CREAT, 0666);
    if (!file_desc) {
        fprintf(stderr, "Unable to open %s for read/write\n", test_file);
        exit(EXIT_FAILURE);
    }


    for (byte_count = 0; byte_count < 100; byte_count++) {
        (void)write(file_desc, byte_to_write, 1);
    }


    region_1.l_type = F_RDLCK;
    region_1.l_whence = SEEK_SET;
    region_1.l_start = 10;
    region_1.l_len = 20;


    region_2.l_type = F_WRLCK;
    region_2.l_whence = SEEK_SET;
    region_2.l_start = 40;
    region_2.l_len = 10;
    //it is ok.
    //region_2.l_start = 10;
    //region_2.l_len = 20;


    printf("Process %d locking file\n", getpid());
    res = fcntl(file_desc, F_SETLK, &region_1);
    if (res == -1)  fprintf(stderr, "Failed to lock region 1\n");
    res = fcntl(file_desc, F_SETLK, &region_2);
    if (res == -1)  fprintf(stderr, "Failed to lock region 2\n");


    sleep(60);

    printf("Process %d closing file\n", getpid());
    close(file_desc);
    exit(EXIT_SUCCESS);
}


lock4.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>

const char *test_file = "/tmp/test_lock";
#define SIZE_TO_TRY 5

void show_lock_info(struct flock *to_show);

int main()
{
    int file_desc;
    int res;
    struct flock region_to_test;
    int start_byte;


    file_desc = open(test_file, O_RDWR | O_CREAT, 0666);
    if (!file_desc) {
        fprintf(stderr, "Unable to open %s for read/write", test_file);
        exit(EXIT_FAILURE);
    }


    for (start_byte = 0; start_byte < 99; start_byte += SIZE_TO_TRY) {

        region_to_test.l_type = F_WRLCK;
        region_to_test.l_whence = SEEK_SET;
        region_to_test.l_start = start_byte;
        region_to_test.l_len = SIZE_TO_TRY;
        region_to_test.l_pid = -1;

        printf("Testing F_WRLCK on region from %d to %d\n",
                start_byte, start_byte+SIZE_TO_TRY);

        res= fcntl(file_desc, F_GETLK, &region_to_test);
        if (res == -1) {
            fprintf(stderr, "F_GETLK failed\n");
            exit(EXIT_FAILURE);
        }
        if (region_to_test.l_pid != -1) {
            printf("Lock would fail. F_GETLK returned:\n");
            show_lock_info(&region_to_test);
        } else {
            printf("F_WRLCK - Lock would succeed\n");
        }


        region_to_test.l_type = F_RDLCK;
        region_to_test.l_whence = SEEK_SET;
        region_to_test.l_start = start_byte;
        region_to_test.l_len = SIZE_TO_TRY;
        region_to_test.l_pid = -1;

        printf("Testing F_RDLCK on region from %d to %d\n",
                start_byte, start_byte+SIZE_TO_TRY);

        res= fcntl(file_desc, F_GETLK, &region_to_test);
        if (res == -1) {
            fprintf(stderr, "F_GETLK failed\n");
            //show_lock_info(&region_to_test);
            exit(EXIT_FAILURE);
        }
        if (region_to_test.l_pid != -1) {
            printf("Lock would fail. F_GETLK returned:\n");
            show_lock_info(&region_to_test);
        } else {
            printf("F_RDLCK - Lock would succeed\n");
        }
    }

    close(file_desc);
    exit(EXIT_SUCCESS);
}


void show_lock_info(struct flock *to_show) {

    printf("\tl_type %d, ", to_show->l_type);
    printf("l_whence %d, ", to_show->l_whence);
    printf("l_start %d, ", to_show->l_start);
    printf("l_len %d, ", to_show->l_len);
    printf("l_pid %d\n", to_show->l_pid);
}

先执行lock3 再执行 lock4
./lock3 &
./lock4
不建议 ./lock3 & ./lock4
此处并非严格顺序执行(并行),不能保证lock3执行到sleep时lock4才执行。

建议试试:
1)对lock3 两个锁(RD  WR)的区域设为同一值,看看运行结果。(估计锁的粒度 是进程/线程?)
2)将lock4 fcntl中的GETLK 改成 SETLK, 看看运行结果。(fcntl将返回-1, 而且如果此时查看flock的l_pid,发现并无修改) 

注意:
1)此处的锁都是建议锁,也就是实际上还是可以对被锁文件进行读写的。(可以尝试运行lock3, 再使用gedit打开lock_file,并修改)
建议锁的作用是,至少在你访问前能得知当前是否有进程也在同时使用他。
2)最后提及一下死锁,想一下这种情况:

process A:
lock(file1);
    ...
    sleep(10);
    lock(file2);
    //do someting to file2
    unlock(file2);
    ...
unlock(file1);


process B:
lock(file2);
    ...
    sleep(10);
    lock(file1);
    //do someting to file1
    unlock(file1);
    ...
unlock(file2);

如果同时执行,对于A来说只有获取文件2,执行结束后才释放文件1.而B只有在获取文件1,执行结束后才释放A想要的文件2. 双方都拥有对方想要的元素,但是都不想退让,僵持在那里。这就是死锁。


dbm数据库

轻量级数据库,通过索引dir+文件内容pag 读写数据。
基本操作跟mysql差不多,唯一得说的是Ubuntu下,如何使用dbm:

1, 安装gdbm:
$ sudo apt-get install libgdbm-dev

2, 在c文件中使用:
头文件: #include

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值