最近在学习Linux系统编程,记录一下学习过程中写过的程序,编程语言为C++,系统为Ubuntu 20.04.2 LTS

文章目录

  1. 文件复制:模拟实现cp命令
  2. 递归遍历目录:模拟实现ls -R命令
  3. fork创建子进程
  4. pipe()管道实现进程间通信
  5. mmap()建立映射区
  6. 信号集练习
  7. sigaction()注册信号捕捉函数
  8. signal注册信号捕捉函数
  9. 借助信号捕捉回收子进程
  10. 创建守护进程
  11. thread_create()创建线程
  12. 循环创建多个线程
  13. pthread_join()等待回收线程
  14. pthread_detach()设置线程分离
  15. 线程属性设置线程分离
  16. 互斥锁/互斥量mutex练习
  17. 条件变量 生产者消费者模型
  18. 信号量 生产者消费者模型


1.文件复制:模拟实现cp命令

源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-09 21:00:22
 * @ Modified time: 2021-07-09 21:43:44
 * @ Description:  通过linux下的read和write系统调用,模拟实现cp命令,完成文件复制功能
 */

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <fcntl.h>

using namespace std;

int main(int argc, char* argv[]){
    if(argc!=3){    //检查参数个数是否为3个,若不是,则显示警告后,退出程序
        cout<<"参数非法,请重新输入!\n";
        exit(1);
    }
    int fd1 = open(argv[1],O_RDONLY);   //打开待读取文件
    if(fd1==-1){                        //打开失败
        perror("read error");           //显示错误信息
        exit(1);
    }
    int fd2 = open(argv[2],O_WRONLY|O_TRUNC|O_CREAT,0644); //打开待写入文件,不存在则创建
    if(fd2==-1){                        //打开或创建失败
        perror("write error");          //显示错误信息
        exit(1);
    }
    char buf[1024];  
    int val = 0;    //保存read函数返回值,返回值为0说明已读之文件末尾
    while((val = read(fd1,buf,1024))!=0){
        write(fd2,buf,val);     //写入文件
    }
    cout<<"文件复制完毕,"<<argv[2]<<"已生成!\n";
    close(fd1);     //关闭文件
    close(fd2);
    return 0;
}

运行结果

cp

2.递归遍历目录:模拟实现ls -R命令

源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-12 13:11:40
 * @ Modified time: 2021-07-12 14:25:34
 * @ Description:  模拟实现ls -R命令,完成递归遍历目录
 */

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <sys/stat.h>
#include <dirent.h>
#include <cstring>
#include <stdio.h>

using namespace std;

void isFile(const string& name);

void read_dir(const string dir){
    DIR* dp =  opendir(dir.c_str()); //打开目录
    if(dp == nullptr){      //失败
        perror("opendir error");
        return ;
    }
    struct dirent *sdp;
    while((sdp = readdir(dp)) != nullptr){  //读取目录
        //文件名为“.”或“..”,则跳过
        if(strcmp(sdp->d_name, ".") == 0 || strcmp(sdp->d_name, "..") == 0){
            continue;
        }
        //拼接文件名
        string f_name = string(sdp->d_name,strlen(sdp->d_name));
        string path = dir + "/" + f_name;
        isFile(path);   //递归调用isFile()
    }
    closedir(dp);
    return ;
}

void isFile(const string& name){
    struct stat sbf;
    //获取文件属性,判断文件类型(文件或文件目录)
    int ret = stat(name.c_str(), &sbf);
    if(ret == -1){ //失败
        perror("stat error");
        return ;
    }
    if(S_ISDIR(sbf.st_mode)){   //目录
        read_dir(name);
    }
    //普通文件
    printf("file_size: %-10ld",sbf.st_size); //输出文件大小,左对齐,占10位
    cout << "file_name: " << name <<"\n";    //文件名称
    return ;
}

int main(int argc, char* argv[]){
    //未输入参数,则默认当前目录,已输入参数,则使用输入的参数
    string name = (argc==1) ? "." : argv[1];
    isFile(name);  
    return 0;
}

运行结果

ls -R

3.fork创建子进程

源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-13 09:40:24
 * @ Modified time: 2021-07-13 09:53:10
 * @ Description:  使用fork()创建子进程
 */

#include <iostream>
#include <cstdlib>
#include <unistd.h>

using namespace std;

int main(int argc, char* argv[]){
    cout<<"before fork - 1 ---\n";
    cout<<"before fork - 2 ---\n";
    cout<<"before fork - 3 ---\n";
    cout<<"before fork - 4 ---\n";
    pid_t pid = fork();
    if(pid == -1){
        perror("Fork error");
        exit(1);
    }
    else if(pid==0){
        cout<<"Child process was created!\n";
        cout<<"my pid: "<<getpid();
        cout<<"  my parent pid: "<<getppid()<<"\n";
    }
    else if(pid > 0){
        cout<<"This is parent process. \nMy child is "<<pid;
        cout<<"  my pid: "<<getpid();
        cout<<"  my parent pid: "<<getppid()<<"\n";
    }
    cout<<"This is the end of file.\n";
    return 0;
}

运行结果

fork.png

4.pipe()管道实现进程间通信

源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-15 14:26:32
 * @ Modified time: 2021-07-15 14:44:06
 * @ Description  : pipe()管道练习
 */

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <sys/wait.h>

using namespace std;

int main(int argc, char* argv[]){
    int fd[2];
    int ret = pipe(fd);
    if(ret == -1){
        perror("pipe error");
    }
    pid_t pid = fork();
    if(pid > 0){        //父进程
        close(fd[0]);   //关闭管道的读端
        string str = "Hello pipe!\n";
        write(fd[1],str.c_str(),str.size());    //向管道写数据
        close(fd[1]);
        wait(nullptr);  //回收子进程
    }
    else if(pid == 0){  //子进程
        close(fd[1]);   //关闭管道的写端
        char buf[1024];
        int size = read(fd[0],buf,sizeof(buf)); //从管道读数据
        write(STDOUT_FILENO,buf,size);          //将读到的数据输出到屏幕
        close(fd[0]);
    }
    return 0;
}

运行结果

pipe.png

5.mmap()建立映射区

源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-15 20:51:09
 * @ Modified time: 2021-07-16 15:27:17
 * @ Description  : mmap建立映射区
 */

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>

using namespace std;

int main(int argc, char* argv[]){
    //打开或创建测试文件
    int fd = open("test.txt",O_RDWR | O_CREAT | O_TRUNC, 0644);
    if(fd == -1){
        perror("file open error");
        exit(1);
    }
    int num = unlink("test.txt");   //删除测试文件
    if(num == -1){
        perror("unlink error");
        exit(1);
    }
    ftruncate(fd,50);   //扩展文件大小
    int len = lseek(fd,0,SEEK_END); //获取文件长度
    cout<<len<<"\n";
    //建立映射区
    char *p = (char*)mmap(nullptr,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    if(p==MAP_FAILED){
        perror("mmap error");   //失败,退出程序
        exit(1);
    }
    close(fd);  //关闭文件
    strcpy(p,"this is a test for mmap()");  //向文件写操作
    printf("-----%s-----\n",p);
    int ret = munmap(p,len);    //释放映射区
    if(ret == -1){  //错误
        perror("munmap error");
        exit(1);
    }
    return 0;
}

运行结果

mmap.png

6.信号集练习

源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-16 21:40:55
 * @ Modified time: 2021-07-16 21:54:28
 * @ Description  : 信号集练习
 */

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <signal.h>

using namespace std;

void print_set(sigset_t *set){
    for(int i=1; i<32; ++i){
        if(sigismember(set,i)){
            putchar('1');
        }
        else{
            putchar('0');
        }
  
    }
    printf("\n");
}

int main(int argc, char* argv[]){
    sigset_t set,oldset,pedset;
    int ret = 0;
    sigemptyset(&set);
    sigaddset(&set,SIGINT);
    ret = sigprocmask(SIG_BLOCK,&set,&oldset);
    if(ret == -1){
        perror("sigprocmask error");
        exit(1);
    }
    while(true){
        ret = sigpending(&pedset); 
        if(ret == -1){
            perror("sigpending error");
            exit(1);
        }
        print_set(&pedset);
        sleep(1);
    }  
    return 0;
}

运行结果

signal.png

7.sigaction()注册信号捕捉函数

源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-17 20:34:45
 * @ Modified time: 2021-07-17 20:57:12
 * @ Description  : sigaction()注册信号捕捉函数
 */

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <signal.h>

using namespace std;

void sig_catch(int sigNo){  //回调函数
    cout<<"\nCatch you! sigNo: "<<sigNo<<"\n";
    return ;
}

int main(int argc, char* argv[]){
    struct sigaction act,oldact;
    act.sa_handler = sig_catch;     //设置回调函数
    sigemptyset(&(act.sa_mask));    //清空sa_mask屏蔽字
    act.sa_flags = 0;               //默认值
    int ret = sigaction(SIGINT,&act,&oldact);   //注册信号捕捉函数
    if(ret == -1){
        perror("sigaction error");
        exit(1);
    }
    ret = sigaction(SIGQUIT,&act,&oldact);      //注册信号捕捉函数
    while(true);
    return 0;
}

运行结果

sigaction.png

8.signal注册信号捕捉函数

源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-17 20:38:09
 * @ Modified time: 2021-07-17 20:42:10
 * @ Description  : signal注册信号捕捉函数
 */

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <signal.h>

using namespace std;

void sig_catch(int sigNo){
    cout<<"\nCatch you! sigNo: "<<sigNo<<"\n";
    return ;
}

int main(int argc, char* argv[]){
    signal(SIGINT,sig_catch); 
    while(true); 
    return 0;
}

运行结果

signal_2.png

9.借助信号捕捉回收子进程

源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-17 21:02:18
 * @ Modified Time: 2021-07-17 21:27:45
 * @ Description  : 借助信号捕捉回收子进程
 */

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <sys/wait.h>

using namespace std;

void catch_child(int sigNo){
    pid_t wpid;
    while((wpid = wait(nullptr)) != -1){    //循环回收,防止僵尸进程出现
        cout<<"------catch child,id = "<<wpid<<"\n";
    } 
    return ;
}

int main(int argc, char* argv[]){
    pid_t pid;
    int i;
    for(i=0;i<5;++i){
        if((pid = fork())==0){
            break;
        }
    }
    if(5==i){   //父进程
        cout<<"I am parent, pid = "<<getpid()<<"\n";
        struct sigaction act;
        act.sa_handler = catch_child;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        sigaction(SIGCHLD,&act,nullptr);
        while(true);
    }else{      //子进程
        cout<<"I am child, pid = "<<getpid()<<"\n";
    }
    return 0;
}

运行结果

catch_child.png

10.创建守护进程

创建守护进程步骤

  1. fork创建子进程,父进程退出。所有工作在子进程中进行,形式上脱离了控制终端;
  2. 在子进程中创建新会话,setsid();
  3. 根据需要,改变工作目录,chdir(),防止占用可卸载的文件系统;
  4. 根据需要,重设文件权限掩码,umask();
  5. 根据需要,关闭/重定向文件描述符;
  6. 守护进程业务逻辑

源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-17 22:51:06
 * @ Modified Time: 2021-07-17 23:27:46
 * @ Description  : 创建守护进程
 */

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

using namespace std;

void sys_error(string str){ //错误处理
    perror(str.c_str());
    exit(1);
}

int main(int argc, char* argv[]){
    pid_t pid;
    pid = fork();
    if(pid>0){  //父进程终止
        exit(0);  
    }
    //子进程
    pid = setsid();   //创建新会话
    if(pid == -1){
        sys_error("setsid error");
    }
    int ret = chdir("/home/wangyusong");    //改变工作目录位置
    if(ret == -1){
        sys_error("chdir error");
    }
    umask(0022);            //改变文件访问权限掩码
    close(STDIN_FILENO);    //关闭文件描述符0
    int fd = open("/dev/null",O_RDWR);  //fd->0
    if(fd == -1){
        sys_error("open error");
    }
    dup2(fd,STDOUT_FILENO);     //重定向stdout和stderr
    dup2(fd,STDERR_FILENO);
    while(true);    //模拟守护进程业务
    return 0;
}

运行结果

deamon.png

11.thread_create()创建线程

源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-18 19:15:09
 * @ Modified Time: 2021-07-18 19:31:14
 * @ Description  : pthread_create()创建线程
 */

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <pthread.h>

using namespace std;

void* func(void *arg){
    printf("thread pid = %d, tid = %lu\n",getpid(),pthread_self()); //pthread_self()获取线程id
    return nullptr;
}

int main(int argc, char* argv[]){
    printf("main pid = %d, tid = %lu\n",getpid(),pthread_self());
    pthread_t tid;
    int ret = pthread_create(&tid,nullptr,func,nullptr);        //创建线程
    if(ret != 0){   //错误
        perror("pthread_create error");
        exit(1);
    }
    sleep(1);       //给新创建的线程预留运行时间
    return 0;
}

运行结果

pthread_create()创建线程

12.循环创建多个线程

源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-18 19:31:39
 * @ Modified Time: 2021-07-19 16:42:23
 * @ Description  : 循环创建多个线程
 */

#include <iostream>
#include <cstdlib>
#include <unistd.h>

using namespace std;

void* func(void *arg){
    long i = reinterpret_cast<long>(arg);   //void*转换成int会报错(cast from 'void*' to 'int' loses precision)
    sleep(i);
    printf("-----I'm %ld(th) thread, pid = %d, tid = %lu\n", i+1, getpid(),pthread_self()); 
    return nullptr;
}

int main(int argc, char* argv[]){
    int i, ret;
    pthread_t tid;
    printf("-----main pid = %d, tid = %lu\n",getpid(),pthread_self());
    for(i=0;i<5;++i){   //循环创建线程
        ret = pthread_create(&tid,nullptr,func,reinterpret_cast<void*>(i));
        if(ret != 0){   //错误
            perror("pthread_create error");
            exit(1);
        }
    }
    sleep(i);  
    return 0;
}

运行结果

t循环创建多个线程

13.pthread_join()等待回收线程

源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-18 20:49:19
 * @ Modified Time: 2021-07-19 16:47:15
 * @ Description  : pthread_join()等待回收线程
 */

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <pthread.h>

using namespace std;

struct thrd{
    int var;
    string str;
};

void* func(void* arg){
    return (void*)("hello pthread!");
}

int main(int argc, char* argv[]){
    pthread_t tid;
    struct thrd * reval;
    int ret = pthread_create(&tid,nullptr,func,nullptr);
    if(ret != 0){
        perror("pthread_create error");
        exit(1);
    }
    char *str;
    ret = pthread_join(tid,(void**)&str);
    if(ret != 0){
        perror("pthread_join error");
        exit(1);
    }
    cout<<"child thread exit with msg = \""<< str <<"\"\n";
    pthread_exit(0);
}

运行结果

pthread_join()

14.pthread_detach()设置线程分离

源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-18 22:22:00
 * @ Modified Time: 2021-07-18 22:32:11
 * @ Description  : pthread_detach()设置线程分离
 */

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <pthread.h>

using namespace std;

void* func(void*){
    printf("thread pid = %d, tid = %lu\n",getpid(),pthread_self()); 
    return nullptr;
}

int main(int argc, char* argv[]){
    pthread_t tid;
    int ret = pthread_create(&tid,nullptr,func,nullptr);    //创建线程
    if(ret != 0){   //错误
        fprintf(stderr,"pthread_create error:%s\n",strerror(ret));
        exit(1);
    }
    ret = pthread_detach(tid);  //设置线程分离后,线程终止时会自动清理pcb,无需回收
    if(ret != 0){
        fprintf(stderr,"pthread_detach error:%s",strerror(ret));
        exit(1);
    }
    sleep(1);
    ret = pthread_join(tid,nullptr);  
    //线程分离后,回收线程时tid无效,错误信息为Invalid argument
    if(ret != 0){
        fprintf(stderr,"pthread_join error:%s\n",strerror(ret));
        exit(1);
    }
    printf("main pid = %d, tid = %lu\n",getpid(),pthread_self());
    pthread_exit((void*)0);
}

运行结果

pthread_detach()

15.线程属性设置线程分离

源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-19 14:00:18
 * @ Modified Time: 2021-07-19 14:54:54
 * @ Description  : 线程属性设置线程分离
 */

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <pthread.h>

using namespace std;

void* func(void *arg){
    printf("\nthread pid = %d, tid = %lu\n",getpid(),pthread_self()); //pthread_self()获取线程id
    return nullptr;
}

int main(int argc, char* argv[]){
    pthread_attr_t attr;
    pthread_t tid;
    int ret = pthread_attr_init(&attr);
    if(ret != 0){
        fprintf(stderr,"pthread_attr_init error:%s",strerror(ret));
        exit(1);
    }
    //设置线程属性为分离属性
    ret = pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);  
    if(ret != 0){
        fprintf(stderr,"pthread_attr_setdetachstate error:%s",strerror(ret));
        exit(1);
    }
    //第二个参数:nullptr --> &attr
    ret = pthread_create(&tid,&attr,func,nullptr);
    if(ret != 0){
        fprintf(stderr,"pthread_create error:%s",strerror(ret));
        exit(1);
    }

    ret = pthread_attr_destroy(&attr);
    if(ret != 0){
        fprintf(stderr,"pthread_attr_destory error:%s",strerror(ret));
        exit(1);
    }
  
    //线程属性为分离属性,回收失败(pthread_join error:Invalid argument)
    ret = pthread_join(tid,nullptr);
    if(ret != 0){
        fprintf(stderr,"pthread_join error:%s",strerror(ret));
        exit(1);
    }

    printf("\nmail pid = %d, tid = %lu\n",getpid(),pthread_self());
    pthread_exit(nullptr);
}

运行结果

线程属性设置线程分离

16.互斥锁/互斥量mutex练习

源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-19 15:00:10
 * @ Modified Time: 2021-07-19 15:22:07
 * @ Description  : 互斥锁/互斥量mutex练习
 */

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <time.h>
#include <unistd.h>
#include <pthread.h>

using namespace std;

pthread_mutex_t mutex;  //定义互斥锁

void* func(void*){
    while(true){
        pthread_mutex_lock(&mutex);     //加锁
        cout<<"hello ";
        sleep(rand()%3);
        cout<<"world\n";
        pthread_mutex_unlock(&mutex);   //解锁
        sleep(rand()%3);
    }
}

int main(int argc, char* argv[]){
    pthread_t tid;
    srand(time(nullptr));
    int ret = pthread_mutex_init(&mutex,nullptr);   //初始化互斥锁
    if(ret != 0){
        fprintf(stderr,"pthread_mutex_init error:%s\n",strerror(ret));
        exit(1);
    }
  
    ret = pthread_create(&tid,nullptr,func,nullptr);    //创建线程
    if(ret != 0){
        fprintf(stderr,"pthread_create error:%s",strerror(ret));
        exit(1);
    }

    while(true){
        pthread_mutex_lock(&mutex);     //加锁
        cout<<"HELLO ";
        sleep(rand()%3);
        cout<<"WORLD\n";
        pthread_mutex_unlock(&mutex);   //解锁
        sleep(rand()%3);
    }

    ret = pthread_mutex_destroy(&mutex);    //销毁互斥锁
    if(ret != 0){
        fprintf(stderr,"pthread_mutex_destory error:%s\n",strerror(ret));
        exit(1);
    }
    pthread_exit(nullptr);
}

运行结果

互斥量 mutex

17.条件变量 生产者消费者模型

源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-19 18:13:13
 * @ Modified Time: 2021-07-20 12:24:52
 * @ Description  : 条件变量 生产者消费者模型
 */

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <time.h>
#include <pthread.h>

using namespace std;

//链表作为共享数据,需要被互斥保护
struct msg{
    int num;
    struct msg *next;  
};

struct msg *head;

//静态初始化一个条件变量和一个互斥量
pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

void* consumer(void*){  //消费者函数
    struct msg *mp;
    while(true){
        pthread_mutex_lock(&lock);
        while(head == nullptr){     //无数据
            pthread_cond_wait(&has_product,&lock);
        }
        mp = head;  
        head = mp->next;
        pthread_mutex_unlock(&lock);
        printf("--consumer----%d\n",mp->num);
        free(mp);  
        sleep(rand()%2);
    }
}

void* producer(void*){  //生产者函数
    struct msg *mp;
    while(true){
        mp = (msg*)malloc(sizeof(msg)); //生成结点
        mp->num = rand()%1000+1;        //随即生成数据
        printf("--produce----%d\n",mp->num);
        pthread_mutex_lock(&lock);
        mp->next = head;    //写公共区域
        head = mp;
        pthread_mutex_unlock(&lock);
        //唤醒阻塞在条件变量has_product上的线程
        pthread_cond_signal(&has_product);  
        sleep(2);
    }
}


int main(int argc, char* argv[]){
    srand(time(nullptr));
    pthread_t con_id,pro_id;
    //创建消费者线程
    int ret = pthread_create(&con_id,nullptr,consumer,nullptr);
    if(ret != 0){
        fprintf(stderr,"consumer pthread_create error:%s\n",strerror(ret));
        exit(1);
    }
    //创建生产者线程
    ret = pthread_create(&pro_id,nullptr,producer,nullptr);
    if(ret != 0){
        fprintf(stderr,"producer pthread_create error:%s\n",strerror(ret));
        exit(1);
    }
    //设置线程分离
    pthread_detach(con_id);
    pthread_detach(pro_id);
    //主线程
    pthread_exit(nullptr);
}

运行结果

1条件变量

18.信号量 生产者消费者模型

源代码

/**
 * @ Author: WangYusong
 * @ E-Mail: admin@wangyusong.cn
 * @ Create Time  : 2021-07-19 20:38:46
 * @ Modified Time: 2021-07-19 21:02:26
 * @ Description  : 信号量 生产者消费者模型
 */

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <cstring>
#include <pthread.h>
#include <semaphore.h>

using namespace std;

const int num = 5;

int queue[num];
sem_t blank_num,product_num;    //空格信号量、产品信号量

void* producer(void*){
    int i=0;
    while(true){
        sem_wait(&blank_num);
        queue[i] = rand()%1000 + 1; //产生数据
        printf("---produce--%d\n",queue[i]);
        sem_post(&product_num);
        i = (i+1) % num;
        sleep(2);
    }

}

void* consumer(void*){
    int i=0;
    while(true){
        sem_wait(&product_num);
        printf("---consume--%d\n",queue[i]);
        queue[i]=0;     //消费数据
        sem_post(&blank_num);
        i = (i+1) % num;
        sleep(2);
    }
}

int main(int argc, char* argv[]){
    pthread_t pid,cid;
    sem_init(&blank_num,0,num); //初始化空格信号量为num
    sem_init(&product_num,0,0); //初始化产品信号量为0
    int ret = pthread_create(&pid,nullptr,producer,nullptr);
    if(ret != 0){
        fprintf(stderr,"producer pthread_create error:%s\n",strerror(ret));
        exit(1);
    }
    ret = pthread_create(&cid,nullptr,consumer,nullptr);
    if(ret != 0){
        fprintf(stderr,"consumer pthread_create error:%s\n",strerror(ret));
        exit(1);
    }
    //设置线程分离
    pthread_detach(pid);
    pthread_detach(cid);
    //回收信号量
    sem_destroy(&blank_num);
    sem_destroy(&product_num);
    //主线程
    pthread_exit(nullptr);
}

运行结果

信号量semaphore


THE END.

最后修改:2021 年 07 月 20 日
如果觉得我的文章对你有用,请随意赞赏