linux系统编程之一

1)fcntl的使用方法

fcntl作用:可以用fcntl函数改变一个已打开的文件属性而不必重新打开文件;

cpp 复制代码
堆排序是完全二叉树,但不是排序二叉树;
排序二叉树要求兄弟节点之间有大小关系,比如说左小右大;
堆排序仅要求父亲节点和孩子节点有大小关系;


在vim命令行中,打开另一个文件的操作方法:
输入":e test.txt";复制完程序后(按tab按键查找需要打开的文件),再":e#",回到当前的文件中;

//fcntl的使用方法(获取(修改)文件描述符的权限)
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/fcntl.h>
using namespace std;

int main(int argc, char *argv[])
{
    int flags;
    flags =  fcntl(STDIN_FILENO,F_GETFL); //从标准输入文件描述符中读取文件的flag标志;
    flags |= O_NONBLOCK;
    fcntl(0,F_SETFL,flags); //把修改后的flags写回标准输入文件结构体中去

    char buf[10];
    ssize_t n;
    while(1)
    {
        n = read(0,buf,5);
        sleep(1);
        if(n >= 0) break;
        if(errno != EAGAIN)
        {
            perror("read");
            return -1;
        }
        write(1,"try again?\n",11);
    }
    write(1,buf,n);
    return 0;
}


2)%x和%#x的区别;
	c语言中%x的意思是16进制输出。2、c语言中符合%#的意思是带格式输出;
3)putchar(10); //换行;

4)epoll的学习
需要包含头文件#include <sys/epoll.h>
STDIN_FILENO等的使用,需要包含unistd.h头文件
F_GETFL等的使用,需要包含#include<sys/fcntl.h>头文件
ioctl如果用的话,需要包含头文件#include<sys/ioctl.h>
操作目录是时候,需要添加dirent.h和sys/types.h  注:dirent[戴尔闰他]其实就是 directory entry 的缩写
errno 是记录系统的最后一次错误代码
O_ACCMODE是文件的进入权限,默认是文件可读可写;

5)fcntl的使用方法
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/fcntl.h>
using namespace std;

int main(int argc, char *argv[])
{
    int flags;
    flags = fcntl(atoi(argv[1]),F_GETFL);
    switch (flags & O_ACCMODE)
    {
    case O_RDONLY:
        printf("read only");
        break;
    case O_WRONLY:
        printf("write only");
        break;
    case O_RDWR:
        printf("read write");
        break;            
    default:
        break;
    }
    // printf("flags is: %#x\r\n",flags);
    putchar(10);
    return 0;
}

2)ioctl用于向设备发控制和配置命令

cpp 复制代码
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdlib.h>

using namespace std;

int main(int argc, char *argv[])
{
    struct winsize size;
    if(isatty(1) == 0)
    {
        printf("1 is not tty\r\n");
        exit(1);
    }
    if(ioctl(1,TIOCGWINSZ,&size) < 0)
    {
        perror("ioctl");
        exit(1);
    }
    printf("%drows,%d columns\n",size.ws_row,size.ws_col); //打印当前终端是多少行,多少列
    return 0;
}
//做多线程的时候,功能和入口要分开;避免高内聚,实现低耦合;
//所谓线程池:就是固定的n个线程,抢一个任务队列中的任务;

3)线程池的应用

cpp 复制代码
//线程池计算5000000里面的素数
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <thread>
#include <iostream>
#include <mutex>
#include <functional>
#include <vector>
#include <unordered_map>
#include <queue>
#include <condition_variable>

using namespace std;

class Task
{
private:
    function<void()> func;
public:
    template<typename FUNC_T,typename ...ARGS>
    Task(FUNC_T f,ARGS ...args)
    {
        func = bind(f, forward<ARGS>(args)...);
    }
    void run()
    {
        func();
    }
};

class ThreadPool
{
private:
    std::vector<thread*> trr;
    unordered_map<thread::id,bool> running;
    queue<Task*> task_q; //任务队列
    mutex mtx;
    condition_variable cond;
    bool starting; //线程开始状态

    void stop_running() //毒药方法
    {
        auto id= this_thread::get_id();
        running[id] = false;
        return;
    }

    Task* get_Task()
    {
        unique_lock<mutex> lock(mtx);
        while(task_q.empty()) //防止被假唤醒
        {
            cond.wait(lock);
        }
        Task* t = task_q.front();
        task_q.pop();
        return t;
    }

public:
    ThreadPool(int n = 1) : trr(n),starting(false)
    {
        this->start();
    }
    void worker()
    {
        auto id = this_thread::get_id();
        running[id] = true;
        while( running[id])
        {
            //获取任务            
            Task* t = get_Task();
            //执行            
            t->run(); //动态申请的,所以得用delete删除掉
            delete t;
        }
    }

    void stop()
    {
        for(int i = 0; i<trr.size(); i++)
        {
            add_task(&ThreadPool::stop_running,this);
        }
        for(int i = 0; i<trr.size(); i++)
        {
            trr[i]->join(); //等待者都被毒死
        }
        for(int i = 0; i<trr.size(); i++)
        {
            delete trr[i];
            trr[i] = nullptr;
        }
    }

    void start()
    {
        for(int i = 0; i < trr.size(); i++)
        {
            trr[i] = new thread(&ThreadPool::worker,this);
        }
    }

    template<typename FUNC_T,typename... ARGS>
    void add_task(FUNC_T f,ARGS ...args)
    {
        //上锁
        unique_lock<mutex> lock(mtx);
        task_q.push(new Task(f,forward<ARGS>(args)...));
        //解锁:同时通知队列中有任务的条件已经达成
        cond.notify_one(); //锁被解开
    }

    virtual ~ThreadPool()
    {
        this->stop();
        while(!task_q.empty())
        {
            delete task_q.front();
            task_q.pop();
        }
    }
};

bool is_prime(int x)
{
    for(int i = 2; i*i <= x; i++)
    {
        if(x%i == 0)
            return false;
    }
    return true;
}

int count_prime(int l,int r)
{
    int cnt = 0;
    for(int i = l; i <= r; i++)
    {
        cnt += is_prime(i);
    }
    return cnt;
}

void work(int l,int r,int& ret) //工作线程
{
    cout<<std::this_thread::get_id()<<": begin"<<endl;
   ret = count_prime(l,r);
    cout<<std::this_thread::get_id()<<": end"<<endl;   
}

int main(int argc, char *argv[])
{
    const int batch = 5000000;
    int ret[10];
    ThreadPool tp(5);

    for(int i = 0, j = 1; i <10; i++, j += batch)
    {
        tp.add_task(work,j+batch-1,ref(ret[i]));
    }
    tp.stop();

    int ans = 0;
    for(auto x: ret)
    {
        ans += x;
    }
    cout<<ans<<endl;
    return 0;
}

4)缓冲区的概要

cpp 复制代码
//缓冲分为全缓冲,行缓冲,无缓冲;
//stdout是行缓冲
//stderr是无缓冲
int main(int argc, char** argv)
{
    for(int i = 0; i < 1025; i++) //从测试看,缓冲区是1024;
        fputc('A',stdout); 
    while(1) //不能让程序结束,如果程序结束,则会自动调用写文件操作;
    {
        ;
    }
    return 0;
}

5)open打开方式的mode介绍

cpp 复制代码
S_IRWXU中的S是 stat的意思; 权限位的设置
//如果要用O_CREAT,则要用第3个参数mode,经过测试,如果没有O_CREAT,也能创建文件,但是得到的文件不对;
系统的open的mode用的是S_IRWXU等等,fopen用的如是"r r+"等等; 一个'r',其实带有好多信息;
open中的flags分为必选项和可选项;
errno:错误码,用stderr输出的叫错误描述符
printf("errno = %d\n",errno); //打印错误代码errno
fprintf(stderr,"stderr\n"); //标准出错输出stderr
perror("perror:"); //输出perror:具体错误信息,相当于做翻译用的
printf("strerror:%s\n", strerror(errno)); //输出strerror:具体错误信息

//注意下面两个是不同的头文件
#include<error.h>
#include<errno.h>
3)open的使用方法
int main(int argc, char** argv)
{
    if(argc < 2)
    {
        printf("usage: cmd filename\r\n");
        return -1;
    }
    int fd = open(argv[1],O_WRONLY | O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); //一大堆,其实就是0644
    printf("%s\r\n",argv[1]);
    if(fd < 0)
    {
        perror("open rgv[1]");
        exit(-1);
    }
    else
    {
        perror("open rgv[1]");
    }
    return 0;
}

6)read,write,ftell,rewind,lseek,fseek,fgetc,fputc等函数的使用及测试文件;

cpp 复制代码
4) umask的使用 终端输入umask,则输出0002;
exit(-1)和return (-1)的区别在哪里?
exit是退出当前进程,而retrun退出当前函数,所以exit范围更广;

5)如何用终端的命令,查看函数的返回值呢?"echo $?"就可以了;
在文件创建中,flag设置O_CREAT|O_EXCL,目的是这个文件必须是自己创建的,已有文件不可以。EXCL的全程是:exclusive美 [ɪkˈskluːsɪv] 独有的
说白了就是:当前进程必须自己创建一个新的文件,而不能使用已有的文件!!!

6)ssize_t的第一个s代表的是sign,是有符号的意思;
     n = read(fd,buf,10); //read的第3个参数是希望读10个数据,但具体多少要看返回值n是多少数据;

//read的使用方法
int main(int argc, char** argv)
{
    char buf[128];
    if(argc < 2)
    {
        printf("usage: cmd filename\r\n");
        return -1;
    }
    int fd = open(argv[1],O_RDONLY); 

    ssize_t n = read(fd,buf,10);
    printf("read bytes is %d\r\n",n);
    for(ssize_t i = 0; i < n; i++)
        printf("%c",buf[i]);        
    putchar(10);

     n = read(fd,buf,10); //read的第3个参数是希望读10个数据,但具体多少要看返回值n是多少数据;
    printf("read bytes is %d\r\n",n);
    for(ssize_t i = 0; i < n; i++)
        printf("%c",buf[i]);
    putchar(10);

    close(fd);
    return 0;
}

7) 从终端设备读,通常以行为单位,读到换行符就返回了,再把读到的数据输出到屏幕上;
    ssize_t n = read(STDIN_FILENO,buf,10); //shell一直监视终端stdin是否有数据,
  当一个终端的程序运行起来的时候,shell程序就会退到后台,不运行了,知道终端的程序运行完,才可以使shell继续运行;
int main(int argc, char** argv)
{
    char buf[128];
    ssize_t n = read(STDIN_FILENO,buf,10);
    if(n < 0)
    {
        perror("read stdin");
        exit(-1);
    }
   n = write(STDOUT_FILENO,buf,n);
    if(n < 0)
    {
        perror("write stdin");
        exit(-1);
    }

    return 0;
}


8)程序的三种状态,睡眠状态,和运行状态;运行状态又分两种,正在被调度执行状态和就绪状态;

#define	EWOULDBLOCK	EAGAIN	/* Operation would block */
EWOULDBLOCK == EAGAIN;EWOULDBLOCK = would block 虚拟语气,应该阻塞
终端就是:/dev/tty = STDIN_FILENO|STDOUT_FILENO;

9)非阻塞从终端上读取数据,并打印到屏幕
int main(int argc, char** argv)
{
    char buf[128];
    ssize_t n;
    int fd = open("/dev/tty",O_RDONLY|O_NONBLOCK); //O_RDONLY|O_NONBLOCK
    if(fd < 0)
    {
        perror("open /dev/tty");
        exit(-1);
    }
    while(1)
    {
        ssize_t n = read(fd,buf,10);
        if(n >= 0 )
        {      
            printf("read num %d\r\n",n);            
            write(STDOUT_FILENO,buf,n);            
            break;
        }  
        if(errno != EAGAIN)
        {
            perror("other error");
            exit(-1);
        }
        write(STDOUT_FILENO,"try try?\n",9);
        sleep(1);
    }
    close(fd);
    return 0;
}

10)EOF的使用及fgetc的使用
EOF宏就是-1; //对"-1"的补码是255,按位取反是0;如:while(~(c = fgetc(fp)))
int main(int argc, char** argv)
{
    FILE* fp = fopen("./test.txt","r");
    char c;
    while((c = fgetc(fp)) != EOF) //千万别写成这样: while(c = fgetc(fp) != EOF) 
        printf("%c",c);
    fclose(fp);
    return 0;
}

11)r r+ w w+分别代表:
r:	以只读方式打开文件;
r+:	以读写方式打开文件,原有文件不清除;
w:	以只写方式打开文件,如果文件不存在,则自动创建。如果文件已经存在,把原有的文件内容删除光。再写入新的内容
w+:	以读写模式打开文件,原有文件清空;

int main(int argc, char** argv)
{
    FILE* fp = fopen(argv[1],"w+");
    if(!fp)
    {
        perror("open file");
        exit(-1);        
    }
    fputc('J',fp);
    fputc('L',fp);
    fputc('5',fp);
    int n = fgetc(fp); //如果在fopen中,模式是"w",则输出的是"-1";
    printf("--------   %d\r\n",n);

    fclose(fp);
    return 0;
}


12)利用fgetc和fputc实现文件的拷贝,案例如下
int main(int argc, char** argv)
{
    if(argc < 3)
    {
        printf("uage: cmd + src + dest\r\n");
        return 1;
    }
    FILE* fp1 = fopen(argv[1],"r");
    if(!fp1)
    {
        perror("open read file");
        exit(-1);        
    }

    FILE* fp2 = fopen(argv[2],"w");
    if(!fp2)
    {
        perror("open write file");
        exit(-1);        
    }    
    char c;
    while(~(c = fgetc(fp1)))
        fputc(c,fp2);

    fclose(fp1);
    fclose(fp2);    
    return 0;
}

13)fseek的使用,seek是寻找的意思;fseek函数的功能:设置文件指针stream的位置。
whence is:SEEK_CUR,SEEK_END,SEET_SET;
SEET_SET是从文件指针的开始位置计算,按道理说应该写SEET_START更好;
rewind函数:C程序中的库函数,功能是将文件内部的指针重新指向一个流的开头
ftell函数: 在c语言中,ftell函数用来返回当前文件指针的位置;
//fseek,rewind,ftell等函数的使用案例:
int main(int argc, char** argv) 
{
    FILE* fp = fopen(argv[1],"r+");
    if(!fp)
    {
        perror("open  file");
        exit(-1);        
    }
    // rewind(fp);
    fseek(fp,3,SEEK_SET);
    printf("pos = %d\n",ftell(fp));
    fputc('M',fp);
    fputc('D',fp);
    printf("pos = %d\n",ftell(fp));    
    fclose(fp);
    return 0;
}

14)判断一个文件的大小,案例如下:
int main(int argc, char** argv)
{
    FILE* fp = fopen(argv[1],"r");
    if(!fp)
    {
        perror("open  file");
        exit(-1);        
    }
    fseek(fp,0,SEEK_END);
    printf("file size is: = %d\n",ftell(fp));    
    fclose(fp);
    return 0;
}

14)lseek的使用方法:lseek的返回值是有意义的,会返回文件的pos位置;从0开始计算;
计算文件的开始位置的偏移量;
int main(int argc, char** argv)
{
    char buf[10];
    int n = 0;
    int fd = open("./test2.txt",O_RDONLY);
    if(fd < 0)
    {
        perror("open file");
        exit(1);
    }
    //123MDN789
    n = read(fd,buf,1);
    write(STDOUT_FILENO,buf,n); //Y
    lseek(fd,5,SEEK_CUR);    //如果SEEK_SET,则是N,如果是SEEK_CUR,则是7;
    n = read(fd,buf,1);    
    write(STDOUT_FILENO,buf,n); //N    
    close(fd);
    return 0;
}
相关推荐
lifeng432125 分钟前
Jenkins集成部署(图文教程、超级详细)
运维·jenkins
白手小弟1 小时前
python wxauto库实现微信自动化发送信息、回复、添加好友等
运维·自动化
ii_best1 小时前
ios按键精灵自动化的脚本教程:自动点赞功能的实现
运维·ios·自动化
3DVisionary1 小时前
数字图像相关DIC技术用于机械臂自动化焊接全场变形测量
运维·数码相机·自动化·焊接变形实验·数字图像相关dic技术·自动化焊接全场变形测量·非接触高精度环境适应性全场测量
小伍_Five1 小时前
透视网络世界:计算机网络习题的深度解析与总结【前3章】
服务器·网络·计算机网络
芷栀夏2 小时前
如何在任何地方随时使用本地Jupyter Notebook无需公网IP
服务器·ide·tcp/ip·jupyter·ip
G鲲鹏展翅Y2 小时前
jupyter-lab与实验室服务器远程链接
服务器·jupyter
IT机器猫2 小时前
Docker完整技术汇总
运维·docker·容器
无所不在的物质2 小时前
Jenkins基础教程
运维·云原生·自动化·jenkins
广而不精zhu小白2 小时前
CentOS Stream 9 挂载Windows共享FTP文件夹
linux·windows·centos