linux系统编程之一

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

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


在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用于向设备发控制和配置命令

#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)线程池的应用

//线程池计算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)缓冲区的概要

//缓冲分为全缓冲,行缓冲,无缓冲;
//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介绍

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等函数的使用及测试文件;

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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值