文件
打开文件open
int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode open(pathname,O_RDWR|O_CREAT|O_TRUNC,mode/*0600*/); //O_NONBLOCK打开文件为非阻塞方式,如果不指定默认为阻塞,即对文件读写操作都需要等待操作的返回状态,open函数不仅可以打开文件也可以打开设备, 如open("/dev/tty3",O_RDWR);
读取文件read(函数) 函数原型 ssize_t read(int fd, void *buf, size_t count);
从指定文件描述符fd相应的文件中读取count字节,放到buf中,如果读取成功,返回读取的字节数,失败返回-1
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd;
char buf[10];
char fileName[]="text.txt"; //text.txt里面存了Hello World
fd = open(fileName,O_RDONLY);
if(fd <0)
{
perror("open()");
exit(1);
}
read(fd,buf,10);
puts(buf);
exit(0);
}
//因为buf空间大小为10,所以只输出Hello Worl
3.写文件函数
ssize_t write(int fd, const void *buf, size_t count);如果open()函数打开时使用O_APPEND项,会将写操作的位置移动到文件结尾
4 文件偏移 lseek()
off_t lseek(int fd, off_t offset, int whence);
文件描述fd,所代表的文件,按照whence模式偏移大小offset偏移,如果操作成功返回新的文件偏移量的值,失败返回-1
whence 为 SEEK_SET,则相对于文件开始处,偏移offset个字节
whence为 SEEK_CUR,怎相对于当前位置偏移offset个字节
whence为SEEK_END,则相对于文件末尾,偏移offset个字节(可以用来空洞文件)
5.获得文件状态 fstat()
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
buf指向struct stat的指针
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for file system I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
};
buf
6.
mmap()文件空间映射void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset)
mmap()将文件映射到内存中,通常参数addr指定为NULL,让系统决定映射到什么地址length表示映射的长度
参数flags 为MAP_SHARED :共享内存映射区域,映射区域允许其他进程共享,对映射去写入数据会写入到文件中
MAP_ANONYMOUS :建立匿名映射,此参数会忽略fd,不涉及文件
参数flags必须指定MAP_SHARED 或者MAP_PRIVATE二者之一int munmap(void *addr, size_t length);取消mmap()函数的映射关系
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
#define FILELENGTH 100
int main(int argc, char *argv[])
{
int fd;
char buf[]="write to file AAA";
char *ptr = NULL;
fd = open("mmap.txt",O_RDWR|O_TRUNC|O_CREAT,0600);
if(fd<0)
{
perror("open");
exit(1);
}
lseek(fd,FILELENGTH,SEEK_SET);
write(fd,"Hello World",11);
ptr = mmap(NULL,FILELENGTH+11,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
memcpy(ptr,buf,strlen(buf));
munmap(ptr,FILELENGTH);
close(fd);
return 0;
}
//lseek()偏移到文件111个字节,中间会产出空洞文件,内容'\0'
7.文件属性fcntl()函数
int fcntl(int fd, int cmd, … /* arg */ );
int fcntl(int fd,int cmd,long arg);
int fcntl(int fd,int cmd,struct flock *lock);如果成功,返回值依赖于cmd,如果出错返回值为-1
F_DUPFD 复制文件描述符(cmd = F_DUPFD),获得的新文件描述符作为函数返回值
获得/设置文件描述符(cmd = F_GETFD或者 F_SETFD)
获得/设置记录锁cmd(=F_GETLK,F_SETLK)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int main(int argc, char *argv[])
{
int flags,setflags;
int accmode;
int fd;
fd = open("test.txt",O_RDWR);
if(fd <0)
{
perror("open()");
exit(1);
}
flags = fcntl(fd,F_GETFL,0); //获得文件的状态
if(flags<0)
{
printf("Faild to use fcntl\n");
return -1;
}
accmode = flags & O_ACCMODE; //获得访问模式
if(accmode == O_RDONLY)
printf("stdin read only\n");
else if(accmode == O_WRONLY)
printf("stdin write only\n");
else if(accmode == O_RDWR)
printf("stdin read write\n");
else
printf("stdin unknown mode");
if(flags & O_APPEND)
printf("STDIN APPEND\n");
if(flags & O_NONBLOCK)
printf("STDIN NONBLOCK\n");
setflags |= O_NONBLOCK;
setflags = fcntl(fd,F_SETFL,&setflags);
if(setflags <0)
{
printf("faild to user fcntl\n");
exit(1);
}
char buf[]="hello";
if(write(fd,buf,strlen(buf))<0)
{
perror("write()");
exit(1);
}
close(fd);
return 0;
}
进程和线程
进程终止的五种方式
1.从main函数返回
2.调用exit
3.调用_exit
4.调用abort
5.由一个信号终止
进程间通信
Linux进程间通信和同步方式,包括管道pipe,命名管道fifo,信号量sem,共享内存shm,消息队列msg,以及信号signal
管道一端读,一端写,利用读写方式在进程间传递数据
共享内存是将内存中的一段地址,在多个进程间共享
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。而且,每个数据块被认为含有一个类型,接收进程可以独立地接收含有不同类型值的数据块。
pid_t getpid(void);//获得进程ID
pid_t getppid(void);//获得父进程ID
pid_t fork(void);//创建一个子进程 执行一次 返回两次
int system(const char *command);//调用shell的外部命令在当前进程中开始另一个进程
//exec函数
int execl(const char *path, const char *arg, .../* (char *) NULL */);
int execlp(const char *file, const char *arg, ..../* (char *) NULL */);
int execle(const char *path, const char *arg, .../*, (char *) NULL, char * const envp[] */);
//变参
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);
//在使用fork()和system()函数的时候,系统中会建立一个新的进程,执行调用者的操作,而原来的进程不回存在,直到用户显示的退出; 而exec()函数族会用新的进程代替原有的进程,系统会从新的进程运行,新进程的PID值会与原来进程的PID值相同,与fork()不同的是exec()函数 在执行成功后不回返回,这是因为新的程序已经占用了当前进程的空间和资源
exec
消息队列
//可以无亲缘关系的进程间通信
key_t ftok(const char *pathname, int proj_id);//路径名和项目标识符转换为System V IPC的关键
int msgget(key_t key, int msgflg);
//创建一个新的消息队列,或者访问一个现有的消息队列
//第一个个参数是一个键值,用ftok()生成
//IPC_CREATE:如果在内核中不存在该队列,则创建它
//IPC_EXCL:当与IPC_CREAT一起使用时,如果队列早已存在则出错
msgid = msgget(key,IPC_CREAT|IPC_EXECL|0600);
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
//向队列传递消息
//第一参数书msgget()的返回值
//第二个参数是个缓冲区
//地三个参数是缓冲区大小
//第四个参数 IPC_NOWAIT 非阻塞模式
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
//第二个参数缓冲区地址,获取的消息将存放在这里
//第三个参数代表消息缓冲区结构大小,不包括mytype成员长度
struct msgbuf{
long mtype;
char mtext[1];
};
//可以以这个结果为模板定义自己的消息结构
信号量
信号量是一个计数器,用来控制多个进程资源共享,,常被用来做一个锁机制,在某个进程正在对特定资源进行操作时,信号量可以防止另一个进程去访问它
uinon semun
{
int val;
struct semid_ds *Buf;
unsigned short *array;
struct seminfo *__buf;
}
int semget(key_t key, int nsems, int semflg);
//创建一个信号量 ,的二个参数指定应该创建的信号量的数目,第三个参数是打开信号量的方式.
semid = semget(key,0,IPC_CREAT|0600);
int semop(int semid, struct sembuf *sops, size_t nsops);//信号量操作函数
struct sembuf
{
ushort sem_num;
short sem_op;
short sem_flg;
}
int Sem_p(sem_t semid)
{
struct sembuf sops = {0,+1,IPC_NOWAIT} //增加信号量
return semop(semid,&sops,1);
}
int Sem_v(sem_t semid)
{
struct sembuf sops={0,-1,IPC_NOWAIT}; //减小信号量的值
return semop(semid,&sops,1)
}
int semctl(int semid, int semnum, int cmd, ...);
//第二个参数是将要执行操作的信号量编号,对于信号量集合中的第一个信号量索引是0,cmd代表药在集合上执行的命令
IPC_STAT,IPC_SET,IPC_RMID,GETALL,
共享内存
int shmget(key_t key, size_t size, int shmflg);
void *shmat(int shmid, const void *shmaddr, int shmflg);
用来获取共享内存地址,如果shmaddr参数的值为零 ,则内核自己找i个未映射的区域int shmdt(const void *shmaddr);
//解除内存映射int shmctl(int shmid, int cmd, struct shmid_ds *buf);
IPC_SET:获取内侧段的shmid_ds结构
IPC_RMID:删除
信号
信号时软件中断
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler); //信号处理函数int kill(pid_t pid, int sig);
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
int sigsuspend(const sigset_t *mask);
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);int sigemptyset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
线程
Compile and link with -pthread.
inux下线程创建函数pthread_create()
int pthread_create(pthread_t thread, const pthread_attr_t *attr,void (start_routine) (void ), void *arg);函数pthread_join()用来等待一个线程运行结束。这个函数是阻塞函数,一直到被等待的线程结束为止,函数才返回并且收回被等待线程的资源
int pthread_join(pthread_t thread, void **retval);int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);线程分离
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);线程互斥量
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
示例代码