文章目录

  • 1.Linux c 目录操作函数scandir
  • 2.Linux系统设备(device)的major和minor number
  • 3.state
  • 4.无锁机制----比较交换CAS Compare And Swap
  • 5.dirent
  • 6.sprintf
  • 7.fopen
  • 8.atoi函数
  • 9.strtok
  • 10.strtol

1.Linux c 目录操作函数scandir

(1)

头文件:#include  <dirent.h>

定义函数:int  scandir(const char *dir, struct dirent **namelist, nt (*select)  (const  struct  dirent *), nt (*compar)  (const struct dirent **, const struct dirent**));
  • 函数说明:scandir()会扫描参数dir指定的目录文件,经由参数select指定的函数来挑选目录结构至参数namelist数组中,最后再调用参数compar指定的函数来排序namelist数组中的目录数据。
  • 每次从目录文件中读取一个目录结构后便将此结构传给参数select所指的函数, select函数若不想要将此目录结构复制到namelist数组就返回0,若select为空指针则代表选择所有的目录结构。
  • scandir()会调用qsort()来排序数据,参数compar则为qsort()的参数,若是要排列目录名称字母则可使用alphasort(). 结构dirent定义请参考readdir()
  • 返回值 :成功则返回复制到namelist数组中的数据结构数目,有错误发生则返回-1

2.Linux系统设备(device)的major和minor number

(1)
Linux系的/dev目录下面的的设备文件是用来表示外设的,如/dev/sda1表示第一块硬盘的第一个分区。但是这个/dev/sda1仅仅是方便用户观察,linux内核中表示不同的设备是通过major 和minor number实现的,通过major和minor Number来加载相应的驱动程序。

major number:表示不同的设备类型

minor number:表示同一个设备的的不同分区

例如:

sda和sdb的major number都是8,sda的minor number是0开始, sdb的minor number 是16开始。ttyS的major number 是4.

root@VM-Ubuntu203001:~#ls -l /dev/sd*

brw-rw----1 root disk 8, 0 Apr 12 01:49 /dev/sda

brw-rw----1 root disk 8, 1 Apr 12 01:49 /dev/sda1

brw-rw----1 root disk 8, 2 Apr 12 01:49 /dev/sda2

brw-rw---- 1 root disk 8, 5 Apr 12 01:49 /dev/sda5

root@VM-Ubuntu203001:~#ls -l /dev/ttyS*

crw-rw----1 root dialout 4, 64 Apr 12 01:48 /dev/ttyS0

crw-rw----1 root dialout 4, 65 Apr 12 01:48 /dev/ttyS1

crw-rw----1 root dialout 4, 66 Apr 12 01:48 /dev/ttyS2

crw-rw---- 1 root dialout 4, 67 Apr 12 01:48 /dev/ttyS3

3.state

(1)stat:查看文件或者文件系统的状态 -->可以查看时间等属性
  根据《UNIX环境高级编程》中对于stat函数的解释,stat函数和stat命令一样,都是返回该文件的详细信息。

而函数

int stat(const char *file_name, struct stat *buf);

的作用就是获取文件名为d_name的文件的详细信息,存储在stat结构体中。以下为stat结构体的定义:

struct stat {   
  
        mode_t     st_mode;       //文件访问权限   
  
        ino_t      st_ino;       //索引节点号   
  
        dev_t      st_dev;        //文件使用的设备号   
  
        dev_t      st_rdev;       //设备文件的设备号   
  
        nlink_t    st_nlink;      //文件的硬连接数   
  
        uid_t      st_uid;        //所有者用户识别号   
  
        gid_t      st_gid;        //组识别号   
  
        off_t      st_size;       //以字节为单位的文件容量   
  
        time_t     st_atime;      //最后一次访问该文件的时间   
  
        time_t     st_mtime;      //最后一次修改该文件的时间   
  
        time_t     st_ctime;      //最后一次改变该文件状态的时间   
  
        blksize_t st_blksize;    //包含该文件的磁盘块的大小   
  
        blkcnt_t   st_blocks;     //该文件所占的磁盘块   
  
      };

4.无锁机制----比较交换CAS Compare And Swap

(1)

  • 锁与共享变量
    加锁是一种悲观的策略,它总是认为每次访问共享资源的时候,总会发生冲突,所以宁愿牺牲性能(时间)来保证数据安全。
    无锁是一种乐观的策略,它假设线程访问共享资源不会发生冲突,所以不需要加锁,因此线程将不断执行,不需要停止。一旦碰到冲突,就重试当前操作直到没有冲突为止。
    无锁的策略使用一种叫做比较交换的技术(CAS Compare And Swap)来鉴别线程冲突,一旦检测到冲突产生,就重试当前操作直到没有冲突为止。
  • 无锁如何鉴别冲突
    CAS核心算法:执行函数:CAS(V,E,N)

V表示准备要被更新的变量

E表示我们提供的 期望的值

N表示新值 ,准备更新V的值

算法思路:V是共享变量,我们拿着自己准备的这个E,去跟V去比较,如果E == V ,说明当前没有其它线程在操作,所以,我们把N 这个值 写入对象的 V 变量中。如果 E != V ,说明我们准备的这个E,已经过时了,所以我们要重新准备一个最新的E ,去跟V 比较,比较成功后才能更新 V的值为N。

scandir,major和minor,state,无锁机制----比较交换CAS Compare And Swap,dirent,sprintf,fopen,atoi,strtok,strtol_字符串

5.dirent

(1)
irent结构体,首先我们要弄清楚目录文件(directory file)的概念:这种文件包含了其他文件的名字以及指向与这些文件有关的信息的指针(摘自《UNIX环境高级编程(第二版)》)。从定义能够看出,dirent不仅仅指向目录,还指向目录中的具体文件,readdir函数同样也读取目录下的文件,这就是证据。以下为dirent结构体的定义:

从上述定义也能够看出来,dirent结构体存储的关于文件的信息很少,所以dirent同样也是起着一个索引的作用,如果想获得类似ls -l那种效果的文件信息,必须要靠stat函数了。

通过readdir函数读取到的文件名存储在结构体dirent的d_name成员中

struct dirent   
{   
  long d_ino; /* inode number 索引节点号 */  
     
    off_t d_off; /* offset to this dirent 在目录文件中的偏移 */  
     
    unsigned short d_reclen; /* length of this d_name 文件名长 */  
     
    unsigned char d_type; /* the type of d_name 文件类型 */  
     
    char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符 */  
}

8.atoi函数

标准C库函数
#include <stdlib.h>

原型 : int atoi( const char *str );

功能:将字符串str转换成一个整数并返回结果。参数str 以数字开头,当函数从str
中读到非数字字符则结束转换并将结果返回。
例如:int num = atoi(“1314.012”);
int值为1314

9.strtok

(1)
今天看了看strtok函数,特意找了下Linux内核2.0.1版本的代码,因为在更高版本(至少2.6)已经使用strsep替换了该函数.

函数原型:

char * strtok(char * s,const char * ct)

使用第二个参数ct中的分隔符字符串,分割第一个参数s,ct参数的分隔符可以是任意字符,可以是单个字符的分隔符,也可以是字符串形式的分隔符如:"!,;’/"等,都可以作为分隔符。例如:

s=“abc,def,123;456!/aaa”

ct=",;!/"
s将被分割为为:abc def 123 456 aaa

测试代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main()
{
  char s[] = "abc,def,123;456!/aaa";
  char delim[] = " ,;!/";
 
  char *p = NULL;
  for(p = strtok(s, delim); p != NULL; p = strtok(NULL, delim))
  {
    printf("%s ", p);
  }
  printf("\n");
 
  return 0;
}

[ljq@ycy algorithm]$ gcc strtok.c -o strtok
[ljq@ycy algorithm]$ ./strtok
abc def 123 456 aaa

10.strtol

(1)long int strtol(const char *nptr, char **endptr, int base)

strtol()会将nptr指向的字符串,根据参数base,按权转化为long int, 然后返回这个值。

参数base的范围为2~36,和0;它决定了字符串已被转换为整数的权值。

可以被转换的合法字符依据base而定,举例来说,当base为2时,合法字符为‘0’,‘1’;base为8时,合法字符为‘0’,‘1’,……‘7’;base为10时,合法字符为‘0’,‘1’,……‘9’;base 为16时,合法字符为‘0’,‘1’,……‘9’,‘a’,……‘f’;base为24时,合法字符为‘0’,……‘9’,‘a’,……‘n’,base为36时,合法字符为‘0’,……‘9’,‘a’,……‘z’;等等。其中,不区分大小写,比如,‘A’和‘a’会都会被转化为10。

当字符合法时,‘0’,……‘9’依次被转换为十进制的0~9,‘a’,……‘z’一次北转换为十进制的10~35。
strtol()函数检测到第一个非法字符时,立即停止检测,其后的所有字符都会被当作非法字符处理。合法字符串会被转换为long int, 作为函数的返回值。非法字符串,即从第一个非法字符的地址,被赋给endptr。**endptr是个双重指针,即指针的指针。strtol()函数就是通过它改变endptr的值,即把第一个非法字符的地址传给endptr。

char buffer[20]="10379cend$3";
char *stop;
printf("%d\n",strtol(buffer, &stop, 2));
printf("%s\n", stop);
输出结果:
2
379cend$3