学习系统编程总结

学习系统编程总结_第1张图片
}2}YY@0DZ12E(B8$6~I`_QJ.png

1,文件操作

1.1普通文件操作:

使用open函数创建函数


       #include 
       #include 
       #include 

       int open(const char *pathname, int flags);
       int open(const char *pathname, int flags, mode_t mode);
       int creat(const char *pathname, mode_t mode);

函数功能:打开文件
函数参数:pathname:待打开文件的路径,flags:打开文件的模式
其中flags的参数有:
O_RDONLY 只读模式,
O_WRONLY 只写模式
O_RDWR 读写模式
O_CREAT 创建模式
O_TRUNC
O_EXCL
flag中含有O_CREAT时才会使用到第三个参数mode
S_IRWXU 用户的读写执行权限
S_IRUSR 用户的读权限
S_IWUSR 用户的写权限
S_IXUSR 用户的执行权限
S_IRWXG 用户组的读写执行权限
返回值:文件的编号,为-1时,打开文件失败。

读写文件

使用read创建函数

 #include 

       ssize_t read(int fd, void *buf, size_t count);

参数列表:
fd:打开文件后的编号
buf:将文件读取到指定的字符数组中
count:可以读取文件的最大长度
返回值:
为0时,读到了到文件的末尾,为-1时,表示文件读取结束。。

使用write写文件操作

 #include 

       ssize_t write(int fd, const void *buf, size_t count);

参数列表:
fd:打开文件后的文件编号
buf:将指定的字符数组中的字符读入文件中
count:可以读取长度,常用来填写read函数的返回值

close关闭文件的函数

#include 

       int close(int fd);

参数:
fd:文件的编号

lseek文件定位函数

 #include 
       #include 

       off_t lseek(int fd, off_t offset, int whence);

参数列表:
fd:文件编号
offset:文件的位置
whence:
SEEK_SET
SEEK_CUR
SEEK_END

stat获取文件的属性

#include 
#include 
#include 
       int stat(const char *path, struct stat *buf);
       int fstat(int fd, struct stat *buf);
       int lstat(const char *path, struct stat *buf);

参数列表:
path:文件的路径
buf:文件信息的结构体
可以使用man手册查看结构体的数据

for example:文件的copy

#include
#include
#include
#include
#include

#define BUFFER_SIZE 100

int main(int argc,char *argv[])
{
    if(argc != 3)
    {
        printf("usage:%s \n",argv[0]);
        return 1;
    }   
    
    int src_fd = 0;
    int dst_fd = 0;
    int n = 0;
    char buf[BUFFER_SIZE] = {"\0"};
    char *src_file = argv[1];
    char *dst_file = argv[2];
    char cover_dir = '\0';
    char cover_filename[BUFFER_SIZE] = {'\0'};
    
    if(access(dst_file,F_OK) == 0)
    {
        printf("directorie is exist!!,,Do you want to cover, y or n:");
        scanf("%c",&cover_dir);
        switch(cover_dir)
        {
            case 'y':
            case 'Y':
                {
                    //dst_fd = open(dst_file,O_WRONLY | O_TRUNC,S_IRUSR | S_IWUSR);
                    if((dst_fd = open(dst_file,O_WRONLY | O_TRUNC)) == -1)
                    {
                        perror("open dst error");
                        return -1;
                    }
                }
                break;
            case 'n':
            case 'N':
                {
                    printf("Please resume load of filename:");
                    getchar();
                    scanf("%s",cover_filename);
                    if((dst_fd = open(cover_filename,O_WRONLY | O_TRUNC | O_CREAT,S_IRUSR | S_IWUSR)) == -1)
                    {
                        perror("open dst error\n");
                        return -1;
                    }   
                    break;                  
                }
                break;
            default:
                    printf("Please input again!!!\n");
                    return -1;
        }
    }
    else{
        if((dst_fd = open(dst_file,O_WRONLY | O_TRUNC | O_CREAT,S_IRUSR | S_IWUSR)) == -1)
        {
                            perror("open dst error");
                            return -1;
        }
    }
    if((src_fd = open(src_file,O_RDONLY)) == -1)
    {
        perror("open src error");
        return -1;
    }
    
    while((n = read(src_fd,buf,BUFFER_SIZE)) > 0)
    {
        write(dst_fd,buf,n);
    }
    
    close(src_fd);
    close(dst_fd);
    
    //1.open

    //2.1 read data form src_file
    //2.2 write data to dst_file
    
    //3.close       
    return 0;
}
  • 读写函数必须在while中操作,是循环对字符串得到操作。

1.2目录操作

Linux下一切皆文件

mkdir创建目录

 #include 
 #include 
       int mkdir(const char *pathname, mode_t mode);

参数列表:
pathname:目录创建的路径
mode:目录的模式
返回值:为-1时,表示失败,为0时表示成功

rmdir删除目录

  #include 
       int rmdir(const char *pathname);

参数列表:
目录的路径
返回值:
为0时,代表目录删除成功,为-1代表失败。

opendir打开目录

 #include 
       #include 

       DIR *opendir(const char *name);

参数列表:
name:目录的名称
返回值:返回为NULL时,目录打开失败

readdir读取目录

 #include 
          struct dirent *readdir(DIR *dirp);
          int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);//进行判断是否读取成功

参数列表:
dirp:文件类型和opendir返回值的类型一致
返回值:返回一个结构体,其中d_name数据类型是文件的名称,

closedir关闭程序

#include 
#include 
       int closedir(DIR *dirp);

参数列表:
dirp:opendir打开文件的类型
返回值:0是成功,1是失败

#include
#include
#include
//#include 
#include 
#include 


int main(int argc ,char *argv[])
{
    if(argc != 2)
    {
        printf("usage:%s ",argv[1]);
        return -1;
    }
    
    char *dst_file = argv[1];
    DIR *dirp = NULL;
    struct dirent *dp = NULL;
    struct stat *buf = NULL;

    if((dirp = opendir(dst_file)) == NULL){
        perror("opendir failed!!!");
        return -1;
    }
    while((dp = readdir(dirp)) != NULL){
        if(dp->d_name[0] == '.');
        else
            printf("%s\n",dp->d_name);
    }
     //int stat(const char *path, struct stat *buf);
     int n = stat(dst_file,buf);
     printf("%ld",buf->st_mode);

    closedir(dirp);
    
    return 0;
}
  • readdir必须在while中执行,是逐条读取的

多进程编程

进程的创建和调度

getpid/getppid进程ID号

#include 
       #include 

       pid_t getpid(void);
       pid_t getppid(void);

参数:void
返回值:
分别为当前进程和父进程的进程号

fork复制创建新的进程

#include 
       pid_t fork(void);

参数:void
返回值:为0时代表子进程,>0时为父进程,通常用于区分父子进程的。

exec函数族替换创建新进程

#include 

       extern char **environ;

       int execl(const char *path, const char *arg, ...);
       int execlp(const char *file, const char *arg, ...);
       int execle(const char *path, const char *arg,
                  ..., 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[]);

参数列表:
path:文件路径
arg:参数列表,其后通常都会跟NULL

  • 例子:
#include
#include
#include
#include
#include
#include
#include 

#define DEBUG_MODE 1

#define COM_MAX_LEN 128

int main(int argc,char *argv[])
{
    pid_t pid = 0;
    char command[COM_MAX_LEN] = {'\0'};
    int status = 0;
    char *delim = " ";
    char *str_command[2];
    struct passwd *pw = NULL;
    struct stat file_stat;
    
    memset(&file_stat, 0, sizeof(file_stat));
    
    while(1)
    {
        // 通过文件所有者ID获取文件所有者名称
        pw = getpwuid(file_stat.st_uid);
        printf("%s>", pw->pw_name);
        
        //printf(">>>>>>>>>");
        //uid_t     st_uid;     /* user ID of owner */

        
        fgets(command,COM_MAX_LEN,stdin);
        command[strlen(command)-1] = '\0';
        
        if(strcmp(command,".exit") == 0)
            return 0;
        
        str_command[0] = strtok(command,delim);
        str_command[1] = strtok(NULL,delim);
        //strcpy(str_command[],p);
    
        if((pid = fork()) == 0)
        {
        
            
            printf("in child peocess :%d\n",getpid());
            //利用exec函数将该子进程的执行指令替换
            execlp(str_command[0],str_command[0],str_command[1],NULL);
            //在path路劲中收索执行ls命令
            //2.在path路劲中搜索执行ls -l /命令
            //execlp("ls","ls","-l",NULL);
            return 0;
            
        }
        //防止僵尸进程的产生
        pid = wait(&status);
#if DEBUG_MODE
        printf("in parent process child %d process exit code: \n",pid);
#endif  
    
    }
    return 0;
}

wait/waitpid等待子进程退出

#include 
       #include 

       pid_t wait(int *status);

       pid_t waitpid(pid_t pid, int *status, int options);

参数:
status:
返回值:返回子进程的ID
作用:放置僵尸进程的产生

信号

一直异步通知机制
常用的信号量有:
SIGINT/SIGQUIT/SIGCLARM/SIGCHLD
信号的三种处理方式:默认处理,忽略,自定义函数

  • 注意,信号处理不用做耗时操作

signal/sigaction注册信号处理函数

 #include 

       typedef void (*sighandler_t)(int);
       int sigaction(int signum, const struct sigaction *act,
                     struct sigaction *oldact);

       sighandler_t signal(int signum, sighandler_t handler);
       void ( *signal(int signum, void (*handler)(int)) ) (int);

参数列表:
signum:信号值
handler:信号处理函数
act:信号处理的一个结构体,里边存放的有信号李处的函数指针

kill/组合键发送信号

 #include 
       #include 

       int kill(pid_t pid, int sig);

参数列表:
pid:进程号
sig:信号
返回值:
发送成功为0;

#include
#include
#include
#include

pid_t pid;

void parent_process_sig_handler(int signo);

void child_process_sig_handler(int signo);

int main(int argc,char *argv[])
{
    
    
    signal(SIGINT,parent_process_sig_handler);
    signal(SIGCHLD,parent_process_sig_handler);
    
    if((pid = fork()) == 0)
    {
        while(1)
        {
        
            signal(SIGINT,SIG_IGN);
            signal(SIGUSR1,child_process_sig_handler);
        
            int client_id = 0;
            
            client_id = rand()%100+1;
            printf("load data %dfrom data center..\n",client_id);
            sleep(1);
            printf("process data %ddown...\n",client_id);
        }
    }
    else if(pid > 0)
    {
        while(1);
    }
    else
    {
    
    }
}

void parent_process_sig_handler(int signo)
{
    switch(signo)
    {
        case SIGCHLD:
        printf("SIGCHLD");
        wait(NULL);
        break;
        case SIGINT:
        kill(pid,SIGUSR1);
        break;
        default:
        break;
    }
}

void child_process_sig_handler(int signo)
{
    if(signo == SIGUSR1)
    {
        printf("..%d\n",getpid());
        exit(0);
    }
}

进程间通信

多线程编程

线程的创建和调度

pthread线程库
pthread_create创建线程

 #include 

       int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);

参数列表:
thread:线程ID的地址
attr:NULL
(*start_routine)(void *):线程函数指针,返回值也是一个函数指针类型
arg:传递给函数指针的参数

pthread_join等待获取线程的返回值

 #include 

       int pthread_join(pthread_t thread, void **retval);

参数列表:
thread:线程的ID
retval:(void **)线程的返回值

pthread_exit退出线程

#include 

       void pthread_exit(void *retval);

参数列表:线程结束时的返回值(void *);

pthread_self获取线程自身ID

#include 

       pthread_t pthread_self(void);

参数列表:
void
返回值:线程自身的ID

pthread_equal判断线程是否相等

#include 

       int pthread_equal(pthread_t t1, pthread_t t2);

参数列表:
t1:线程1
t2:线程2
返回值:如果两个线程是相等的,则返回的是非0的数值
否则,为0

pthread_cancel取消指定线程

 #include 

       int pthread_cancel(pthread_t thread);

参数列表:
thread:线程ID
返回值:如果成功返回值为0,失败则返回一个非零的数值

#include
#include
#include

struct thread_arg
{
    int thread_no;
    int lower;
    int upper;
};

struct thread_arg argument1,argument2;

void *add_thread_func(void *arg);

int main(int argc,char *argv[])
{
    pthread_t thread_id1;
    pthread_t thread_id2;
    int *psum1 = NULL;
    int *psum2 = NULL;
    
    argument1.thread_no = 1;
    argument1.lower = 1;
    argument1.upper = 500;
    pthread_create(&thread_id1,NULL,add_thread_func,&argument1);
    
    argument2.thread_no = 2;
    argument2.lower = 501;
    argument2.upper = 1000;
    pthread_create(&thread_id2,NULL,add_thread_func,&argument2);
    
    pthread_join(thread_id1,(void **)&psum1);
    pthread_join(thread_id2,(void **)&psum2);
    
    printf("sum = %d\n",*psum1 + *psum2);
    
    free(psum1);
    free(psum2);
    
    return 0;
}

void *add_thread_func(void *arg)
{
     struct thread_arg *p_arg = (struct thread_arg *)arg;
     int i = 0;
     int sum = 0;
     int *psum = (int *)malloc(sizeof(int));
     
     for(i = p_arg->lower;i < p_arg->upper+1;i++)
        sum += i;
     
     //printf("in thread no %d :sum = %ld\n",p_arg->thread_no,sum);
     *psum = sum;
     
     pthread_exit(psum);
}

线程并发要求

同步:进程、线程中部分指令需要按照一定顺序执行
异步:进程、线程的指令执行顺序无序
互斥:对共享的资源操作只能有一个线程或进程
竞争:对有限资源的共享产生的竞争关系
死锁:互相等待资源
饥饿:长时间无法获得资源

线程间通信

  • 1,信息交换:使用多个线程都可见的内存区域
  • 2,线程互斥锁:保障有同一把锁保护的共享资源被多个线程互相访问

pthread_mutex_t互斥锁

互斥锁的类型

pthread_mutex_init互斥锁初始化
pthread_mutex_lock互斥锁的获取(加锁)
pthread_mutex_unlock互斥锁的释放(解锁)

#include
#include
#include

struct thread_arg
{
    int thread_no;
    int lower;
    int upper;
};

struct thread_arg argument1,argument2;

void *add_thread_func(void *arg);

int main(int argc,char *argv[])
{
    pthread_t thread_id1;
    pthread_t thread_id2;
    int *psum1 = NULL;
    int *psum2 = NULL;
    
    argument1.thread_no = 1;
    argument1.lower = 1;
    argument1.upper = 500;
    pthread_create(&thread_id1,NULL,add_thread_func,&argument1);
    
    argument2.thread_no = 2;
    argument2.lower = 501;
    argument2.upper = 1000;
    pthread_create(&thread_id2,NULL,add_thread_func,&argument2);
    
    pthread_join(thread_id1,(void **)&psum1);
    pthread_join(thread_id2,(void **)&psum2);
    
    printf("sum = %d\n",*psum1 + *psum2);
    
    free(psum1);
    free(psum2);
    
    return 0;
}

void *add_thread_func(void *arg)
{
     struct thread_arg *p_arg = (struct thread_arg *)arg;
     int i = 0;
     int sum = 0;
     int *psum = (int *)malloc(sizeof(int));
     
     for(i = p_arg->lower;i < p_arg->upper+1;i++)
        sum += i;
     
     //printf("in thread no %d :sum = %ld\n",p_arg->thread_no,sum);
     *psum = sum;
     
     pthread_exit(psum);
}
  • 线程信号量:解决多个线程在使用有限共享资源时的同步问题

sem_t线程信号量

线程信号量的数据类型

sem_init信号量的初始化

#include 

       int sem_init(sem_t *sem, int pshared, unsigned int value);

参数列表:
sem:信号量的名称地址
pshared:一般为0
value:线程信号量的初始值
返回值:成功为0,失败为-1

sem_wait信号量获取(-1)

 #include 
       int sem_wait(sem_t *sem);

参数列表:
sem:线程信号量的地址,通常需要加地址符
返回值:成功为0,失败为-1

sem_post信号量的释放(+1)

 #include 
       int sem_post(sem_t *sem);

参数列表:
sem:线程信号量的地址,通常需要加地址符
返回值:成功为0,失败为-1

sem_destroy信号量的销毁

#include 
       int sem_destroy(sem_t *sem);

参数列表:
sem:线程信号量的地址,通常需要加地址符
返回值:成功为0,失败为-1

*例子:

#include
#include
#include
#include
#include

sem_t sem;

void *thread_func(void *arg);

void sig_handler(int signo);

int main(int argc,char *argv[])
{
    pthread_t thread_id;
    
    //注册信号发送函数
    signal(SIGINT,sig_handler);
    
    //初始化信号量,值为0
    sem_init(&sem,0,0);
    
    pthread_create(&thread_id,NULL,thread_func,NULL);
    
    pthread_join(thread_id,NULL);
    
    printf("main....\n");
    
    //销毁信号量
    sem_destroy(&sem);
    
    return 0;
}

void *thread_func(void *arg)
{
    while(1)
    {
        sem_wait(&sem);
        //信号量减一
        printf("thread func...\n");
        
        sleep(3);
    }
    
    pthread_exit(NULL);
}

void sig_handler(int signo)
{
    if(signo == SIGINT)
    {
        sem_post(&sem);
        //信号量加一
    }
    
    pthread_exit(NULL);
}

进程的执行状态:新建、就绪、运行、阻塞、退出
僵尸进程:自己进程退出之后,没有父进程wait
孤儿进程:父进程在子进程之前退出,该子进程称为孤儿进程,进而被init进程收养

你可能感兴趣的:(学习系统编程总结)