Beginning Linux Programming 笔记(七)数据管理

来源:互联网 发布:sd格式化后数据恢复 编辑:程序博客网 时间:2024/04/30 02:23

数据管理,这对每一个操作系统而言都是必须的。操作系统对数据的管理,可以分成三个方面,内存数据管理,文件管理和抽象数据管理。

内存数据管理

内存的管理应该对大部分C程序员都不陌生,对指针的内存分配是编程时经常会用到的。内存数据管理有下面几个主要函数:

#include<stdlib.h>

void *malloc(size_t size);

void free(void *ptr_to_memory);

void *calloc(size_t number_of_elements, size_t element_size);

void *realloc(void *exist_memory, size_t newsize);

有一个地方必须注意,有一些系统是用malloc.h文件来调用内存管理程序,我在window下面写C程序时就是用malloc.h这个文件。 malloc()函数会创建大小为size个字节的内存空间,free()函数可以释放内存。这一点可能就是C/C++一直被java取笑的地方,对于内存的处理,内存垃圾都需要程序员去释放处理,而java提供了强大的内存垃圾处理功能,大大减轻程序员的负担。其实这里并没有泼C/C++冷水的意思,只是阐述了C在内存处理方面的不足,但也是它的这种不足,这种面向底层的特点,才让C程序员对整个系统有绝对的控制权。像我们的java老师说过的一句话:能用java实现的东西都能用C实现。这也是C语言多年依旧在语言排行榜上面稳居前三的原因。

扯得有点远了,回到我们的内存处理函数。calloc()与malloc的区别是calloc是用块的思想去分配的,程序员使用元素个数,还有每个元素单元大小去分配内存。本质上是一样的,calloc(n, m) 跟malloc(n*m)的作用是等效的。realloc()相当于先使用free(exist_memory),再malloc(newsize)。因此,使用malloc()跟free()就其实就足以覆盖内存处理的大部分功能了。

 

文件锁

对于文件的读写操作,有一个很重要的地方我们没提过,那就是读写冲突。假设有一种情况,A、B用户在想读写文件test,把里面的一个变量加1,他们都在对方写入硬盘之前读到变量,结果就造成了写入冲突。本来两个人执行的结果应该是加2,现在变成了加1。程序变得不可预测,所以我们需要去消解这种冲突。

解决文件共享的冲突有两种方法,一种是使用信号量,后面14章会详细地叙述(不过我也不清楚我是否能看到第十四章,哈),另一种是使用文件锁,下面做具体介绍。

#include <fcntl.h>

int fcntl(int fildes, int command, struct flock *flock_structure);

fildes是文件的id,也即是这个函数只能适用于用底层文件操作。

command是一个常量,有三个选项,表示文件锁控制行为

F_GETLK     (get lock)                        读取文件锁

F_SETLK     (set lock)               设置文件锁

F_SETLKW   (set lock or wait)        设置文件锁,如果不成功,则等待

struct flock是文件锁的结构体

short l_type;      F_RDLCK(读文件锁) F_UNLCK(解锁)  F_WRLCK(写文件锁)

short l_whence;  SEEK_SET, SEEK_CUR, 或 SEEK_END,参考前面底层文件操作

short l_start;        文件锁起点

short l_len;       文件锁长度

short l_pid;       文件锁进程id

 

下面有两个例子:

region_1.l_type = F_RDLCK;

region_1.l_whence = SEEK_SET;

region_1.l_start = 10;

region_1.l_len = 20;

res = fcntl(file_desc, F_SETLK, &region_1);

对文件10-30字节这个区间增加一个读文件锁

 

region_2.l_type = F_WRLCK;

region_2.l_whence = SEEK_SET;

region_2.l_start = 40;

region_2.l_len = 10;

res = fcntl(file_desc, F_SETLK, &region_2);

对文件40-50字节这个区间增加一个写文件锁。

 

读文件锁跟写文件锁是不一样的。对于读文件,我们可以允许多个程序同时读,但是此时,写入明显就是不妥的。对于一个进程在写文件时,读写文件都是不允许的,都有可能造成冲突。

要注意的是,文件锁只是返回逻辑判断的结果,而没有真正限制到读写函数本身如何去执行。也即是文件锁提供的只是一个读写冲突的建议,具体如何操作那就要看你程序怎么做了。

 

dbm数据库

Linux大部分都提供了dbm数据管理工具,这个一个非结构化查询语言(noSQL)。个人感觉它是SQL的雏形,思想上面有挺多地方是一致的。

dbm数据管理的思想是给数据建立索引,做数据查询时可以通过索引去查询,而不是完全扫描整行记录。并且,系统把插入跟查询都给封装起来,让用户跟方便检索。

struct datum {

  void *dptr;        //数据指针

  size_t dsize;       //数据长度

};

#include <gdbm-ndbm.h>  /* 有些系统使用 #include<ndbm.h> */

DBM *dbm_open(const char *filename, int file_open_flags, mode_t file_mode);  创建

int dbm_store(DBM *database_descriptor, datum key, datum content, int store_mode)

插入数据,key存储的是索引,content是存储数据。

datum dbm_fetch(DBM *database_descriptor, datum key);     检索,key对应索引数据

void dbm_close(DBM *database_descriptor)                关闭

对于DBM类型的创建,跟文件创建是相似的,我就不多说了。

数据的存储有一个参数,store_mode,控制着存储行为的处理。当值为store_insert,遇到索引重复时也会插入数据;当值为store_replace时,遇到索引重复时会直接替代,而不是插入一条新数据。因此,这个函数也可以用来更新数据,功能跟MYSQL的update类似。

 

对于文件的编译,由于引入了一些库,所以要加一些选项跟参数。

编译 dbm1.c这个文件的例子:

使用ndbm.h库的用户:

gcc –o dbm1 –I/usr/include/gdbm dbm1.c –lgdbm

使用gdbm-ndbm.h库的用户:

gcc –o dbm1 –I/usr/include/gdbm dbm1.c –lgdbm –lgdbm_compat

 

上面就是我关于数据管理一章的一些总结,说得不对的地方,还请大家多多指出。

原创粉丝点击