当前位置: 技术问答>linux和unix
请教高手:多线程访问时如何实现删除一个文件?
来源: 互联网 发布时间:2015-01-25
本文导语: 如下要求: 当某一线程欲删除一个文件时,如果另外一些线程正在访问该文件。那么这些线程仍然可以对该文件进行操作。直到所有这些线程关闭了这个文件。该文件才被删除。也就是说,只要有一个线程还打开着...
如下要求:
当某一线程欲删除一个文件时,如果另外一些线程正在访问该文件。那么这些线程仍然可以对该文件进行操作。直到所有这些线程关闭了这个文件。该文件才被删除。也就是说,只要有一个线程还打开着这个文件,该文件的物理空间就没有真正地被删除。(假设是单级目录,即只有根目录)
结构:
////////////////////////////////////
位图模块
class BitMap {
public:
BitMap(int nitems); // 初始化方法,给出位图的大小,将所有位标明未用
~BitMap(); // 析构方法
void Mark(int which); // 标志第which位被占用
void Clear(int which); // 清除第which位
bool Test(int which); //测试第which位是否被占用,若是,返TRUE
int Find(); //找到第一个未被占用的位,标志其被占用;
// 若没有找到,返回-1
int NumClear(); // 返回多少位没有被占用
void Print(); // 打印出整个位图(调试用)
void FetchFrom(OpenFile *file); //从一个文件中读出位图
void WriteBack(OpenFile *file); //将位图内容写入文件
private:
... //内部实现属性
};
////////////////////////////////////
文件头的定义
class FileHeader {
public:
bool Allocate(BitMap *bitMap, int fileSize);
// 通过文件大小初始化文件头
// 根据文件大小申请磁盘空间
void Deallocate(BitMap *bitMap); // 将一个文件占用的数据空间释放
// (没有释放文件头占用的空间)
void FetchFrom(int sectorNumber); // 从磁盘扇区中取出文件头
void WriteBack(int sectorNumber); // 将文件头写入磁盘扇区
int ByteToSector(int offset); // 文件逻辑地址向物理地址的转换
int FileLength(); // 返回文件长度
void Print(); // 打印文件头信息(调试用)
private:
int numBytes; //文件长度(字节数)
int numSectors; //文件占用的扇区数
int dataSectors[NumDirect]; //文件索引表
};
///////////////////////////////////
文件系统模块:
class FileSystem {
public:
FileSystem(bool format); // 生成方法
bool Create(char *name, int initialSize); //生成一个文件
OpenFile* Open(char *name); //打开一个文件
bool Remove(char *name); //删除一个文件
void List(); //列出文件系统中所有的文件
//(实际上就是根目录中所有的文件)
void Print(); //列出文件系统中所有的文件和它们的内容
private:
OpenFile* freeMapFile; //位图文件打开文件结构
OpenFile* directoryFile; //根目录打开文件结构
};
////////////////////////////////////
Remove方法
语法: bool Remove (char *name)
参数: name:需要删除的文件名
功能: 在当前的文件系统中删除一个已有的文件
实现: 在根目录下搜寻该文件名
1. 如果没有搜索到,返回FALSE
2. 如果搜索到,打开该文件并返回打开文件控制块
2.1. 将该文件从目录中删除
2.2. 释放FileHeader所占用的空间
2.3. 释放文件数据块占用的空间
2.4. 将对位图和目录的修改写回磁盘
返回: 如果删除成功,返回TRUE;否则返回FALSE
bool FileSystem::Remove(char *name)
{
Directory *directory;
BitMap *freeMap;
FileHeader *fileHdr;
int sector;
directory = new Directory(NumDirEntries);
directory->FetchFrom(directoryFile);
sector = directory->Find(name);
if (sector == -1) {
delete directory;
return FALSE; // file not found
}
fileHdr = new FileHeader;
fileHdr->FetchFrom(sector);
freeMap = new BitMap(NumSectors);
freeMap->FetchFrom(freeMapFile);
fileHdr->Deallocate(freeMap); // remove data blocks
freeMap->Clear(sector); // remove header block
directory->Remove(name);
freeMap->WriteBack(freeMapFile); // flush to disk
directory->WriteBack(directoryFile); // flush to disk
delete fileHdr;
delete directory;
delete freeMap;
return TRUE;
}
如何修改remove方法和相应的文件结构,实现上面的要求?
当某一线程欲删除一个文件时,如果另外一些线程正在访问该文件。那么这些线程仍然可以对该文件进行操作。直到所有这些线程关闭了这个文件。该文件才被删除。也就是说,只要有一个线程还打开着这个文件,该文件的物理空间就没有真正地被删除。(假设是单级目录,即只有根目录)
结构:
////////////////////////////////////
位图模块
class BitMap {
public:
BitMap(int nitems); // 初始化方法,给出位图的大小,将所有位标明未用
~BitMap(); // 析构方法
void Mark(int which); // 标志第which位被占用
void Clear(int which); // 清除第which位
bool Test(int which); //测试第which位是否被占用,若是,返TRUE
int Find(); //找到第一个未被占用的位,标志其被占用;
// 若没有找到,返回-1
int NumClear(); // 返回多少位没有被占用
void Print(); // 打印出整个位图(调试用)
void FetchFrom(OpenFile *file); //从一个文件中读出位图
void WriteBack(OpenFile *file); //将位图内容写入文件
private:
... //内部实现属性
};
////////////////////////////////////
文件头的定义
class FileHeader {
public:
bool Allocate(BitMap *bitMap, int fileSize);
// 通过文件大小初始化文件头
// 根据文件大小申请磁盘空间
void Deallocate(BitMap *bitMap); // 将一个文件占用的数据空间释放
// (没有释放文件头占用的空间)
void FetchFrom(int sectorNumber); // 从磁盘扇区中取出文件头
void WriteBack(int sectorNumber); // 将文件头写入磁盘扇区
int ByteToSector(int offset); // 文件逻辑地址向物理地址的转换
int FileLength(); // 返回文件长度
void Print(); // 打印文件头信息(调试用)
private:
int numBytes; //文件长度(字节数)
int numSectors; //文件占用的扇区数
int dataSectors[NumDirect]; //文件索引表
};
///////////////////////////////////
文件系统模块:
class FileSystem {
public:
FileSystem(bool format); // 生成方法
bool Create(char *name, int initialSize); //生成一个文件
OpenFile* Open(char *name); //打开一个文件
bool Remove(char *name); //删除一个文件
void List(); //列出文件系统中所有的文件
//(实际上就是根目录中所有的文件)
void Print(); //列出文件系统中所有的文件和它们的内容
private:
OpenFile* freeMapFile; //位图文件打开文件结构
OpenFile* directoryFile; //根目录打开文件结构
};
////////////////////////////////////
Remove方法
语法: bool Remove (char *name)
参数: name:需要删除的文件名
功能: 在当前的文件系统中删除一个已有的文件
实现: 在根目录下搜寻该文件名
1. 如果没有搜索到,返回FALSE
2. 如果搜索到,打开该文件并返回打开文件控制块
2.1. 将该文件从目录中删除
2.2. 释放FileHeader所占用的空间
2.3. 释放文件数据块占用的空间
2.4. 将对位图和目录的修改写回磁盘
返回: 如果删除成功,返回TRUE;否则返回FALSE
bool FileSystem::Remove(char *name)
{
Directory *directory;
BitMap *freeMap;
FileHeader *fileHdr;
int sector;
directory = new Directory(NumDirEntries);
directory->FetchFrom(directoryFile);
sector = directory->Find(name);
if (sector == -1) {
delete directory;
return FALSE; // file not found
}
fileHdr = new FileHeader;
fileHdr->FetchFrom(sector);
freeMap = new BitMap(NumSectors);
freeMap->FetchFrom(freeMapFile);
fileHdr->Deallocate(freeMap); // remove data blocks
freeMap->Clear(sector); // remove header block
directory->Remove(name);
freeMap->WriteBack(freeMapFile); // flush to disk
directory->WriteBack(directoryFile); // flush to disk
delete fileHdr;
delete directory;
delete freeMap;
return TRUE;
}
如何修改remove方法和相应的文件结构,实现上面的要求?
|
由操作系统释放,OS知道哪些进程打开了哪些文件。
创建一个临时文件的典型做法就是用创建方式打开一个文件,然后马上unlink,
但你可以继续使用这个文件句柄读/写,当你close后磁盘空间才被释放。
创建一个临时文件的典型做法就是用创建方式打开一个文件,然后马上unlink,
但你可以继续使用这个文件句柄读/写,当你close后磁盘空间才被释放。
|
unix就是这样做的。当你删除一个文件时,它的目录项被马上删除。但是只要还有进程打开了该文件,文件所占用的磁盘块就没有释放,直到最后一个进程关闭该文件,文件所占磁盘空间才释放。
建议:多看点Unix系统的书,少看点C++的书。
建议:多看点Unix系统的书,少看点C++的书。
|
up
|
那你首先要实现对文件的打开记数。
|
用互斥和计数器,可以参照微软的com技术中的关于addRef和release方法
|
那你是要在核心态实现还是用户态?
如果在核心态,根据文件系统的数据结构是可以实现的。
如果在用户态,嘿嘿,我看够戗。
我不了解你的什么nachos。只是随便说说,说错了别见怪。
如果在核心态,根据文件系统的数据结构是可以实现的。
如果在用户态,嘿嘿,我看够戗。
我不了解你的什么nachos。只是随便说说,说错了别见怪。