嵌入式Linux开发学习记录(4)

一,进程间通信方式实现

1. 使用无名管道实现父子进程之间通信

#include <unistd.h>
#include <stdio.h>
#include <string.h>

#define TEST_STRING "123456789"
//使用无名管道实现父子进程之间通信
int pipe_test()
{
    int fd[2] = {0};  // fd数组存储管道的两端,fd[0]用于读取,fd[1]用于写入
    int ret = pipe(fd);  // 创建管道
    if(ret == -1)  // 检查管道是否创建成功
    {
        perror("pipe");  // 创建失败时打印错误信息
        return -1;  // 返回-1表示出错
    }
    ret = fork();  // 创建子进程
    if(ret == 0)  // 子进程执行的代码块
    {
        close(fd[0]);  // 子进程关闭管道的读取端,因为它只负责写入
        while(1)
        {
            write(fd[1], TEST_STRING, strlen(TEST_STRING));  // 子进程循环写入数据到管道
            sleep(1);  // 每次写入后暂停1秒
        }
    }
    else if(ret > 0)  // 父进程执行的代码块
    {
        close(fd[1]);  // 父进程关闭管道的写入端,因为它只负责读取
        while(1)
        {
            char buf[128] = {0};  // 定义缓冲区存储从管道读取的数据
            read(fd[0], buf, 128);  // 父进程从管道读取数据
            printf("buf:%s\n", buf);  // 打印读取的数据
        }
    }
    else
    {
        perror("fork");  // fork失败时打印错误信息
    }

    return 0;
}

int main(int argc, char *argv[])
{
    pipe_test();  // 调用pipe_test函数
    return 0;
}

 运行效果

hui@hui-virtual-machine:~/projects/tongxin$ vim pipe.c
hui@hui-virtual-machine:~/projects/tongxin$ gcc pipe.c -o pipe
hui@hui-virtual-machine:~/projects/tongxin$ ls
fifo2.c  msg2.c  pipe     pipe.c       posix_mq.c   posix_shm.c  shm.c
fifo.c   msg.c   pipe2.c  posix_mq2.c  posix_sem.c  sem.c
hui@hui-virtual-machine:~/projects/tongxin$ ./pipe
buf:123456789
buf:123456789
buf:123456789
buf:123456789
buf:123456789
buf:123456789
buf:123456789
buf:123456789
buf:123456789
buf:123456789
^C
hui@hui-virtual-machine:~/projects/tongxin$ 

2.使用无名管道实现兄弟进程之间通信

#include <unistd.h>
#include <stdio.h>
#include <string.h>

//使用无名管道实现兄弟进程之间通信
int pipe_test()
{
    int fd[2] = {0};  // 存储管道两端的文件描述符
    int ret = pipe(fd);  // 创建无名管道
    if(ret == -1)
    {
        perror("pipe");  // 如果管道创建失败,打印错误信息
        return -1;  // 返回-1表示出错
    }
    ret = fork();  // 创建第一个子进程
    if(ret == 0)  // 如果是第一个子进程
    {
        close(fd[0]);  // 关闭读端,因为这个子进程只负责写
        while(1)
        {
            write(fd[1], TEST_STRING, strlen(TEST_STRING));  // 循环写入字符串到管道
            sleep(1);  // 每次写入后暂停1秒
        }
    }
    else if(ret > 0)  // 如果是父进程
    {
        close(fd[1]);  // 关闭写端,父进程不写入数据
        int r = fork();  // 再创建一个子进程(第二个子进程)
        if (r == 0)  // 如果是第二个子进程
        {
            while(1)
            {
                char buf[128] = {0};  // 创建缓冲区
                read(fd[0], buf, 128);  // 从管道读取数据
                printf("buf:%s\n", buf);  // 打印接收到的数据
            }
        }
        // 这里,父进程可以选择等待子进程结束或进行其他操作,但当前代码中未处理。
    }
    else
    {
        perror("fork");  // 如果fork失败,打印错误信息
    }

    return 0;  // 函数返回0表示正常结束
}

int main(int argc,char *argv[])
{
    pipe_test();  // 执行pipe_test函数
    return 0;  // 主函数返回0
}

 3.使用命名管道完成进程间通信

#include <sys/types.h> 
#include <sys/stat.h>  
#include <stdio.h>     
#include <errno.h>     
#include <fcntl.h>     
#include <unistd.h>   
#include <string.h>    
#include <stdlib.h>    

// 使用命名管道完成进程间通信
// 两个进程运行程序,一个读,一个写
#define FIFO_PATH "/tmp/test"  // 定义管道文件的路径

int fifo_read()
{
    int ret = mkfifo(FIFO_PATH, 0644);  // 创建命名管道,权限为 0644
    if ((ret == -1) && (errno != EEXIST))  // 如果创建失败且错误不是已存在
    {
        perror("mkfifo");  // 打印错误消息
        return -1;  // 返回错误代码
    }
    int fd = open(FIFO_PATH, O_RDONLY);  // 以只读方式打开管道
    if (fd == -1)  // 如果打开失败
    {
        perror("open");  // 打印错误消息
        return -1;  // 返回错误代码
    }

    while (1)  // 无限循环,持续读取数据
    {
        char buf[1024] = {0};  // 创建缓冲区,初始化为0
        read(fd, buf, 1024);  // 从管道读取数据到缓冲区
        printf("buf:%s\n", buf);  // 打印读取的数据
    }

    return 0;  // 返回0,表示成功
}

int fifo_write(const char *buf)  // 参数 buf 指向要写入管道的字符串
{
    int ret = mkfifo(FIFO_PATH, 0644);  // 创建命名管道,权限为 0644
    if ((ret == -1) && (errno != EEXIST))  // 如果创建失败且错误不是已存在
    {
        perror("mkfifo");  // 打印错误消息
        return -1;  // 返回错误代码
    }
    int fd = open(FIFO_PATH, O_WRONLY);  // 以只写方式打开管道
    if (fd == -1)  // 如果打开失败
    {
        perror("open");  // 打印错误消息
        return -1;  // 返回错误代码
    }

    while (1)  // 无限循环,持续写入数据
    {
        write(fd, buf, strlen(buf));  // 将 buf 指向的数据写入管道
        sleep(1);  // 暂停1秒
    }

    return 0;  // 返回0,表示成功
}

int main(int argc, char *argv[])  // 主函数,接收命令行参数
{
    int mode = atoi(argv[1]);  // 将第一个命令行参数转换为整数,决定模式(读或写)
    char *buf = argv[2];  // 第二个命令行参数,指向要写入的字符串
    if (mode == 0)  // 如果模式为0,执行读操作
    {
        fifo_read();  // 调用读函数
    }
    else  // 否则,执行写操作
    {
        fifo_write(buf);  // 调用写函数,传入字符串
    }
    return 0;  // 返回0,表示成功
}

运行效果 

4.使用命名管道完成父子进程间通信

#include <sys/types.h> 
#include <sys/stat.h>  
#include <stdio.h>     
#include <errno.h>     
#include <fcntl.h>     
#include <unistd.h>    
#include <string.h>   
#include <stdlib.h>    

#define FIFO_PATH "/tmp/test"  // 定义管道文件的路径

int fifo_read()
{
    int ret = mkfifo(FIFO_PATH, 0644);  // 创建命名管道,权限为 0644
    if ((ret == -1) && (errno != EEXIST))  // 如果创建失败且错误不是已存在
    {
        perror("mkfifo");  // 打印错误消息
        return -1;  // 返回错误代码
    }
    int fd = open(FIFO_PATH, O_RDONLY);  // 以只读方式打开管道
    if (fd == -1)  // 如果打开失败
    {
        perror("open");  // 打印错误消息
        return -1;  // 返回错误代码
    }

    while (1)  // 无限循环,持续读取数据
    {
        char buf[1024] = {0};  // 创建缓冲区,初始化为0
        read(fd, buf, 1024);  // 从管道读取数据到缓冲区
        printf("buf:%s\n", buf);  // 打印读取的数据
    }

    return 0;  // 返回0,表示成功
}

int fifo_write(const char *buf)  // 参数 buf 指向要写入管道的字符串
{
    int ret = mkfifo(FIFO_PATH, 0644);  // 创建命名管道,权限为 0644
    if ((ret == -1) && (errno != EEXIST))  // 如果创建失败且错误不是已存在
    {
        perror("mkfifo");  // 打印错误消息
        return -1;  // 返回错误代码
    }
    int fd = open(FIFO_PATH, O_WRONLY);  // 以只写方式打开管道
    if (fd == -1)  // 如果打开失败
    {
        perror("open");  // 打印错误消息
        return -1;  // 返回错误代码
    }

    while (1)  // 无限循环,持续写入数据
    {
        write(fd, buf, strlen(buf));  // 将 buf 指向的数据写入管道
        sleep(1);  // 暂停1秒
    }

    return 0;  // 返回0,表示成功
}

int test()  // 测试函数,用于演示父子进程间的通信
{
    int ret = mkfifo(FIFO_PATH, 0644);  // 创建命名管道,权限为 0644
    if ((ret == -1) && (errno != EEXIST))  // 如果创建失败且错误不是已存在
    {
        perror("mkfifo");  // 打印错误消息
        return -1;  // 返回错误代码
    }
    
    ret = fork();  // 创建子进程
    if (ret == 0)  // 如果当前进程是子进程
    {
        int fd = open(FIFO_PATH, O_RDONLY);  // 子进程以只读方式打开管道
        if (fd == -1)
        {
            perror("open");  // 打印错误消息
            return -1;  // 返回错误代码
        }

        while (1)  // 子进程无限循环,持续读取数据
        {
            char buf[1024] = {0};  // 创建缓冲区
            read(fd, buf, 1024);  // 从管道读取数据到缓冲区
            printf("buf:%s\n", buf);  // 打印读取的数据
        }

    }
    else if (ret > 0)  // 如果当前进程是父进程
    {
        int fd = open(FIFO_PATH, O_WRONLY);  // 父进程以只写方式打开管道
        if (fd == -1)
        {
            perror("open");  // 打印错误消息
            return -1;  // 返回错误代码
        }

        while (1)  // 父进程无限循环,持续写入数据
        {
#define  TEST_STRING "123456789"  
            write(fd, TEST_STRING, strlen(TEST_STRING));  // 写入定义的字符串到管道
            sleep(1);  // 暂停1秒
        }
    }
    else  // 如果 fork 失败
    {
        perror("fork");  // 打印错误消息
        return -1;  // 返回错误代码
    }
    return 0;  // 返回0,表示成功
}

int main(int argc, char *argv[])
{
#if 1
    test();  // 调用测试函数,展示父子进程通信
#else
    int mode = atoi(argv[1]);  // 根据命令行参数确定操作模式(读或写)
    char *buf = argv[2];  // 获取要写入的字符串
    if (mode == 0)  // 如果模式为0,执行读操作
    {
        fifo_read();  // 调用读函数
    }
    else  // 否则,执行写操作
    {
        fifo_write(buf);  // 调用写函数
    }

#endif
    return 0;  // 返回0,表示程序成功结束
}

运行效果

5.消息队列实现进程间通信

#include <sys/types.h> 
#include <sys/ipc.h>   
#include <stdlib.h>    
#include <unistd.h>    
#include <string.h>   

#define _USE_GNU
#include <sys/msg.h>   
#include <stdio.h>    

// 消息队列实现进程间通信
int main(int argc, char* argv[]) {
    int mode = atoi(argv[1]);  // 从命令行获取模式,0 为读取,非0 为发送
    int mtype = atoi(argv[2]); // 从命令行获取消息类型
    char *str = argv[3];       // 从命令行获取要发送的字符串

    key_t key = 1234;  // 设置消息队列的键值,进程通过它来访问队列
    int id = msgget(key, 0644 | IPC_CREAT); // 创建或访问一个消息队列
    printf("id:%d\n", id); // 打印消息队列标识符

    while (1) {
        if (mode == 0) {  // 读模式
            struct msgbuf {
                long mtype;     // 消息类型
                char mtext[1024];  // 消息数据
            } msg = {0};  // 初始化消息结构

            int ret = msgrcv(id, &msg, 1024, mtype, 0); // 从队列接收消息
            if (ret == -1) {
                perror("msgrcv"); // 如果接收失败,打印错误信息
                break;
            }
            printf("ret:%d,type:%lu,mtext:%s\n", ret, msg.mtype, msg.mtext);
        } else {  // 发送模式
            struct msgbuf {
                long mtype;     // 消息类型
                char mtext[1024];  // 消息数据
            } msg = {0};  // 初始化消息结构

            msg.mtype = mtype;  // 设置消息类型
            memcpy(msg.mtext, str, strlen(str)); // 复制字符串到消息文本
            int ret = msgsnd(id, &msg, strlen(str), 0); // 发送消息
            if (ret == -1) {
                perror("msgsnd"); // 如果发送失败,打印错误信息
                break;
            }
            sleep(1); // 每次发送后暂停一秒
        }
    }

    msgctl(id, IPC_RMID, NULL); // 删除消息队列
    return 0;
}

运行效果

6.获取消息队列状态

#include <sys/types.h> 
#include <sys/ipc.h>   
#include <stdlib.h>    
#include <unistd.h>    
#include <string.h>    

#define _USE_GNU
#include <sys/msg.h>   
#include <stdio.h>     

// 三种创建key的方式,获取消息队列状态
int main(int argc, char* argv[]) {

    int mode = atoi(argv[1]);  // 模式,0为接收,非0为发送
    int mtype = atoi(argv[2]); // 消息类型
    char *str = argv[3];       // 发送的字符串

    // 创建key
    // 方式1:直接指定
    // key_t key = 1234;

    // 方式2:使用IPC_PRIVATE
    // key_t key = IPC_PRIVATE;

    // 方式3:使用ftok()
    key_t key = ftok("/tmp/test", 1);
    if (key == -1) {
        perror("ftok");
        return -1;
    }

    int id = msgget(key, 0644 | IPC_CREAT); // 创建或获取消息队列
    printf("id:%d\n", id);

    struct msqid_ds stat; // 用于获取队列状态的结构

    while (1) {
        if (mode == 0) { // 接收模式
            struct msgbuf {
                long mtype;      // 消息类型
                char mtext[1024]; // 消息数据
            } msg = {0};

            int ret = msgrcv(id, &msg, 1024, mtype, 0); // 接收消息
            if (ret == -1) {
                perror("msgrcv");
                break;
            }
            printf("ret:%d, type:%lu, mtext:%s\n", ret, msg.mtype, msg.mtext);
        } else { // 发送模式
            struct msgbuf {
                long mtype;      // 消息类型
                char mtext[1024]; // 消息数据
            } msg = {0};

            msg.mtype = mtype;
            memcpy(msg.mtext, str, strlen(str));
            int ret = msgsnd(id, &msg, strlen(str), 0); // 发送消息
            if (ret == -1) {
                perror("msgsnd");
                break;
            }

            // 获取并打印消息队列状态
            if (msgctl(id, IPC_STAT, &stat) == -1) {
                perror("msgctl - stat");
                break;
            }
            printf("msg queue nums:%lu, bytes:%lu\n", stat.msg_qnum, stat.__msg_cbytes);
            sleep(1);
        }
    }

    msgctl(id, IPC_RMID, NULL); // 删除消息队列
    return 0;
}

运行效果

7.使用信号量完成进程间同步

#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <sys/sem.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>

//使用信号量完成进程间同步

// 定义一个联合体,用于信号量操作
union semun
{
    int val;                // 用于 SETVAL 的值
    struct semid_ds *buf;   // 用于 IPC_STAT 和 IPC_SET
    unsigned short *array;  // 用于 GETALL 和 SETALL
    struct seminfo *_buf;   // 用于 IPC_INFO
    void *_pad;             // 扩展用途
};

// 初始化信号量的值
int sem_init_value(int id, int num, int value)
{
    union semun un;
    un.val = value;  // 设置要初始化的值
    int ret = semctl(id, num, SETVAL, un);  // 设置信号量的值
    if (ret == -1)
    {
        perror("semctl SETVAL");
        return -1;
    }
    printf("sem init value:%d\n", value);
    return 0;
}

// 获取信号量的当前值
int sem_get_value(int id, int num)
{
    union semun un;
    int ret = semctl(id, num, GETVAL, un);  // 获取信号量的值
    if (ret == -1)
    {
        perror("semctl GETVAL");
        return -1;
    }
    printf("sem get value:%d\n", ret);
    return 0;
}

// P 操作:申请资源,使信号量减一
int sem_p(int id)
{
    struct sembuf buf;
    buf.sem_num = 0;  // 指定操作的信号量索引
    buf.sem_op = -1;  // 指定操作类型,-1 表示申请资源
    buf.sem_flg = SEM_UNDO;  // 确保程序退出时撤销操作
    int ret = semop(id, &buf, 1);  // 执行操作
    if (ret == -1)
    {
        perror("sem p");
        return -1;
    }
    return 0;
}

// W 操作:等待信号量为零
int sem_w(int id)
{
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = 0;  // 操作为等待信号量变为0
    buf.sem_flg = SEM_UNDO;
    int ret = semop(id, &buf, 1);
    if (ret == -1)
    {
        perror("sem w");
        return -1;
    }
    return 0;
}

// V 操作:释放资源,使信号量加一
int sem_v(int id)
{
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = 1;  // 操作类型为释放资源
    buf.sem_flg = SEM_UNDO;
    int ret = semop(id, &buf, 1);
    if (ret == -1)
    {
        perror("sem v");
        return -1;
    }
    return 0;
}

// 主函数
int main(int argc, char *argv[])
{
    int op = atoi(argv[1]);  // 操作类型
    int value = atoi(argv[2]);  // 信号量初始值或操作参数

    key_t key = ftok("/tmp/test", 1);  // 生成键值
    if (key == -1)
    {
        perror("ftok");
        return -1;
    }

    int id = semget(key, 5, 0644 | IPC_CREAT);  // 获取或创建信号量集
    printf("id:%d\n", id);

    if (value >= 0)
    {
        sem_init_value(id, 0, value);  // 初始化信号量值
    }
    sem_get_value(id, 0);  // 获取并打印信号量值

    if (op == 1)  // 根据操作参数执行不同的操作
    {
        sem_p(id);
    }
    else if (op == 0)
    {
        sem_w(id);
    }
    else
    {
        sem_v(id);
    }
    sem_get_value(id, 0);  // 再次获取并打印信号量值
    pause();  // 等待信号

    // 清理资源
    // sleep(5);
    // union semun un;
    // semctl(id, 0, IPC_RMID, un);  // 删除信号量集
    return 0;
}

运行效果

8.使用共享内存进行进程间通信

#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/sem.h>
#include <errno.h>
//使用共享内存完成进程间通信,使用信号量实现共享内存访问同步
// 信号量联合体,用于信号量操作参数
union semun {
    int val;                // 用于SETVAL的值
    struct semid_ds *buf;   // 用于IPC_STAT和IPC_SET
    unsigned short *array;  // 用于GETALL和SETALL
    struct seminfo *_buf;   // 用于IPC_INFO(Linux特有)
    void *_pad;             // 其他用途,保证联合体大小足够
};
int sem_init_value(int id, int num, int value) {
    union semun un;
    un.val = value;  // 设置信号量的初始值
    int ret = semctl(id, num, SETVAL, un);  // 设置信号量的值
    if (ret == -1) {
        perror("semctl SETVAL");
        return -1;
    }
    printf("sem init value:%d\n", value);
    return 0;
}


int sem_get_value(int id, int num) {
    union semun un;
    int ret = semctl(id, num, GETVAL, un);  // 读取信号量的值
    if (ret == -1) {
        perror("semctl GETVAL");
        return -1;
    }
    printf("sem get value:%d\n", ret);
    return 0;
}


int sem_p(int id) {
    struct sembuf buf;
    buf.sem_num = 0;  // 信号量索引
    buf.sem_op = -1;  // 信号量减1,等待操作
    buf.sem_flg = SEM_UNDO;  // 确保程序退出时撤销操作
    int ret = semop(id, &buf, 1);  // 执行P操作
    if (ret == -1) {
        perror("sem p");
        return -1;
    }
    return 0;
}


int sem_w(int id) {
    struct sembuf buf;
    buf.sem_num = 0;  // 指定操作的信号量索引为0
    buf.sem_op = 0;   // 指定操作类型为等待信号量变为0
    buf.sem_flg = SEM_UNDO;  // 设置操作标志为SEM_UNDO,确保程序异常退出时系统自动撤销该操作

    int ret = semop(id, &buf, 1);  // 对指定的信号量执行操作,这里的1表示操作数组中只有一个操作结构
    if (ret == -1) {
        perror("sem w");  // 如果操作失败,打印错误信息
        return -1;        // 返回错误码-1
    }
    return 0;  // 操作成功,返回0
}


int sem_v(int id) {
    struct sembuf buf;
    buf.sem_num = 0;  // 信号量索引
    buf.sem_op = 1;   // 信号量加1,释放操作
    buf.sem_flg = SEM_UNDO;  // 确保程序退出时撤销操作
    int ret = semop(id, &buf, 1);  // 执行V操作
    if (ret == -1) {
        perror("sem v");
        return -1;
    }
    return 0;
}




int main(int argc, char *argv[]) {
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <mode> <value>\n", argv[0]);
        return EXIT_FAILURE;
    }
    int mode = atoi(argv[1]);  // 模式:0读,1写
    int value = atoi(argv[2]);  // 信号量初始值或操作值

    // 创建信号量
    key_t semkey = ftok("/tmp/test", 2);
    if (semkey == -1) {
        perror("ftok");
        return -1;
    }
    int semid = semget(semkey, 5, 0644 | IPC_CREAT);
    printf("semid:%d\n", semid);
    if (value >= 0) {
        sem_init_value(semid, 0, value);
    }
    sem_get_value(semid, 0);

    // 创建共享内存
    key_t shmkey = ftok("/tmp/test", 1);
    if (shmkey == -1) {
        perror("ftok");
        return -1;
    }
    int shmid = shmget(shmkey, 1024, 0644 | IPC_CREAT);
    void *addr = shmat(shmid, NULL, 0);
    if (addr == (void *) -1) {
        perror("shmat");
        return -1;
    }

    // 数据处理循环
    int i = 0;
    while (1) {
        if (mode == 0) {  // 读模式
            sem_p(semid);  // 等待信号量
            char rbuf[1024] = {0};
            memcpy(rbuf, addr, 1024);
            printf("rbuf:%s\n", rbuf);
            sem_v(semid);  // 释放信号量
        } else {  // 写模式
            char wbuf[1024] = {0};
            sprintf(wbuf, "%d", i++);
            memset(addr, 0, 1024);
            memcpy(addr, wbuf, strlen(wbuf));
            sem_v(semid);
            sleep(1);
        }
    }

    // 清理资源(实际上在while循环中不会被执行)
    shmdt(addr);  // 分离共享内存
    shmctl(shmid, IPC_RMID, NULL);  // 删除共享内存
    return 0;
}

 运行效果

9.使用POSIX消息队列实现进程间通信

#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

//编译加-lrt
//使用POSIX消息队列完成进程间通信

int main(int argc, char *argv[])
{
    int mode = atoi(argv[1]);  // 从命令行参数获取模式

    // 检查是否需要删除消息队列
    if(mode == -1)
    {
        mq_unlink("/test1");  // 删除消息队列
        return 0;
    }

    struct mq_attr attr;       // 定义消息队列属性
    attr.mq_flags = 0;         // 消息队列标志,0表示阻塞模式
    attr.mq_maxmsg = 10;       // 最大消息数
    attr.mq_msgsize = 1500;    // 单个消息最大大小

    // 创建或打开消息队列
    mqd_t fd = mq_open("/test1", O_RDWR | O_CREAT, 0644, &attr);
    if(fd == -1)
    {
        perror("mq_open");  // 打开或创建失败时打印错误
        return -1;
    }

    while (1)
    {
        if(mode == 0)  // 消息接收模式
        {
            char rbuf[2048] = {0};  // 接收缓冲区
            unsigned int prio = 0;  // 消息优先级
            int ret = mq_receive(fd, rbuf, 2048, &prio);  // 接收消息
            if(ret == -1)
            {
                perror("mq_receive");  // 接收失败时打印错误
                break;
            }
            printf("ret:%d, prio:%u, rbuf:%s\n", ret, prio, rbuf);  // 打印接收的消息和信息
        }
        else  // 消息发送模式
        {
            int ret = mq_send(fd, TEST_STRING, strlen(TEST_STRING), 1);  // 发送消息
            if(ret == -1)
            {
                perror("mq_send");  // 发送失败时打印错误
                break;
            }
            sleep(1);  // 发送消息后暂停1秒
        }
    }
    
    return 0;
}

运行效果

10.使用POSIX信号量完成进程间通信

#include <fcntl.h>
#include<sys/stat.h>
#include<semaphore.h>
#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>


//编译加-lpthread
//使用POSIX信号量完成多进程同步
int main(int argc,char*argv[])
{
    int mode = atoi(argv[1]);  // 从命令行参数获取运行模式

    // 尝试打开或创建一个名为 "/test" 的POSIX信号量,初始计数值为0
    sem_t *sem = sem_open("/test", O_RDWR | O_CREAT, 0644, 0);
    if(sem == SEM_FAILED)  // 检查信号量是否成功打开或创建
    {
        perror("sem_open");  // 打印错误信息
        return -1;  // 出错时退出程序
    }

    while(1)  // 进入无限循环
    {
        if(mode == 0)  // 模式0: 等待信号量(消费者模式)
        {
            sem_wait(sem);  // 阻塞等待信号量,直到信号量大于0时才继续执行
            printf("sem--\n");  // 打印信号量减少的信息
        }
        else  // 其他模式: 发布信号量(生产者模式)
        {
            sleep(1);  // 每次操作前暂停1秒
            printf("sem++\n");  // 打印信号量增加的信息
            sem_post(sem);  // 释放信号量,增加信号量的计数值
        }
    }
    // 以下两行在 while(1) 循环外,实际上不会被执行到,因为上面的循环是无限循环
    sem_close(sem);  // 关闭信号量
    sem_unlink("/tmp");  // 移除信号量对象
    return 0;  // 程序正常结束
}

运行效果

11.使用POSIX共享内存进行进程间通信

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include<unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
//使用共享内存完成进程间通信
//编译加-lrt
//使用POSIX信号量完成线程同步TODO
int main(int argc, char* argv[])
{
    if(argc < 2) { // 检查命令行参数是否足够
        printf("Usage: %s <mode>\n", argv[0]);
        return 1;
    }

    int mode = atoi(argv[1]); // 从命令行参数获取模式
    int fd = shm_open("/test2", O_RDWR | O_CREAT, 0644); // 打开或创建共享内存对象
    if(fd == -1)
    {
        perror("shm_open"); // 打开共享内存失败时打印错误
        return -1;
    }

    int ret = ftruncate(fd, 4096); // 设置共享内存对象的大小为4096字节
    if(ret == -1)
    {
        perror("ftruncate"); // 设置大小失败时打印错误
        return -1;
    }

    void *addr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); // 映射共享内存
    if(addr == MAP_FAILED)
    {
        perror("mmap"); // 映射失败时打印错误
        return -1;
    }

    while(1)
    {
        if(mode == 0) // 模式0为读模式
        {
            char rbuf[4096] = {0};
            memcpy(rbuf, addr, 4096); // 从共享内存复制数据到缓冲区
            printf("rbuf:%s\n", rbuf); // 打印读取的数据
        }
        else // 其他模式为写模式
        {
            static int i = 0; // 静态变量用于保存递增的值
            char wbuf[4096] = {0};
            sprintf(wbuf, "%d", i++); // 将递增的整数格式化到缓冲区
            memcpy(addr, wbuf, strlen(wbuf) + 1); // 将缓冲区数据复制到共享内存
            sleep(1); // 每次写入后暂停1秒
        }
    }
    // 清理资源,虽然在无限循环中不会执行到
    munmap(addr, 4096); // 取消映射
    close(fd); // 关闭共享内存对象
    shm_unlink("/test2"); // 删除共享内存对象

    return 0;
}

运行效果

 二,生产者消费者模型

#include <stdio.h>      // 引入标准输入输出库
#include <stdlib.h>     // 引入标准库,用于常规函数
#include <pthread.h>    // 引入线程库,用于多线程编程
#include <errno.h>      // 引入错误号库,用于错误处理
#include <semaphore.h>  // 引入信号量库,用于线程同步
#include <unistd.h>     // 提供通用的文件、目录、程序及进程操作的函数
#include <fcntl.h>      // 文件控制选项
#include <sys/types.h>  // 引入数据类型定义
#include <sys/stat.h>   // 引入与文件状态相关的定义

#define BUFFER 20      // 定义缓冲区大小为20
#define BATCH_SIZE 3   // 每批处理的字符数量

sem_t empty, full;     // 定义两个信号量,empty和full
pthread_mutex_t mutex; // 定义互斥锁
char buffer[BUFFER];   // 定义缓冲区数组
int bufferin = 0, bufferout = 0; // 定义缓冲区的输入输出位置指针
int fp;                // 定义文件指针
int done = 0;          // 定义完成标志,用于通知消费者停止

// 生产者函数
void* producers() 
{
    char in[BATCH_SIZE]; // 定义一个字符数组,用于批量读取字符
    int readone;

    printf("开始生产者读取...\n");
    while ((readone = read(fp, in, BATCH_SIZE)) > 0) 
    { // 循环读取文件内容,每次读取BATCH_SIZE个字符
        printf("成功读取 %d 字符...\n", readone);
        for (int i = 0; i < readone; i++) 
        { // 对于每个成功读取的字符
            sem_wait(&empty); // 等待一个空的缓冲区位
            pthread_mutex_lock(&mutex); // 上锁,进入临界区

            buffer[bufferin] = in[i]; // 将字符放入缓冲区
            printf("Producer put %c in buffer at %d\n", in[i], bufferin); // 打印生产者放入字符的信息
            bufferin = (bufferin + 1) % BUFFER; // 更新缓冲区的输入位置

            pthread_mutex_unlock(&mutex); // 解锁
            sem_post(&full); // 增加满缓冲区的计数
        }
        sleep(1); // 模拟延时,假设生产过程需要时间
    }

    if (readone == -1) 
    {
        perror("read failed"); // 如果读取失败,输出错误信息
    }

    done = 1; // 设置完成标志
    for (int i = 0; i < BATCH_SIZE; i++) 
    { // 确保所有消费者可以终止
        sem_post(&full);
    }
    printf("生产者结束读取...\n");
    return NULL;
}

// 消费者函数
void* consumers() 
{
    printf("消费者开始工作...\n");
    while (1)
    {
        char items[BATCH_SIZE]; // 定义一个数组用于存储批量消费的数据

        for (int i = 0; i < BATCH_SIZE; i++)
        {
            sem_wait(&full); // 等待一个满的缓冲区位
            pthread_mutex_lock(&mutex); // 上锁,进入临界区

            if (done && bufferout == bufferin)
            { // 如果生产者完成且缓冲区被消费完
                pthread_mutex_unlock(&mutex); // 解锁
                for (; i < BATCH_SIZE; i++) sem_post(&empty); // 确保释放所有空位
                break; // 跳出循环,终止消费者线程
            }

            items[i] = buffer[bufferout]; // 从缓冲区取出字符
            buffer[bufferout] = '\0'; // 清空缓冲区位
            printf("Consumer consumed %c from buffer at %d\n", items[i], bufferout); // 打印消费信息
            bufferout = (bufferout + 1) % BUFFER; // 更新缓冲区的输出位置

            pthread_mutex_unlock(&mutex); // 解锁
            sem_post(&empty); // 增加空缓冲区的计数
        }


        if (done && bufferout == bufferin)
        {
            printf("消费者结束工作...\n");
            break; // 如果生产已完成且所有数据都已消费,终止循环
        }

        sleep(2); // 模拟延时,假设消费过程需要时间
       
    }
    return NULL;// 确保循环结束后正常返回
}

int main() {
    pthread_t producer[3], consumer[4]; // 定义生产者和消费者线程数组
    fp = open("/home/hui/test", O_RDONLY); // 打开文件
    if (fp == -1) {
        perror("open failed"); // 如果文件打开失败,输出错误信息并退出
        exit(1);
    }

    sem_init(&empty, 0, BUFFER); // 初始化empty信号量,大小为缓冲区大小
    sem_init(&full, 0, 0);       // 初始化full信号量,初始为0
    pthread_mutex_init(&mutex, NULL); // 初始化互斥锁

    for (int i = 0; i < 3; i++) // 创建生产者线程
        pthread_create(&producer[i], NULL, producers, NULL);
    for (int i = 0; i < 4; i++) // 创建消费者线程
        pthread_create(&consumer[i], NULL, consumers, NULL);

    for (int i = 0; i < 3; i++) // 等待生产者线程完成
        pthread_join(producer[i], NULL);
    for (int i = 0; i < 4; i++) // 等待消费者线程完成
        pthread_join(consumer[i], NULL);

    pthread_mutex_destroy(&mutex); // 销毁互斥锁
    sem_destroy(&empty); // 销毁empty信号量
    sem_destroy(&full); // 销毁full信号量
    close(fp); // 关闭文件
    printf("所有线程已结束。\n");
    return 0;
}

开始生产者读取...
消费者开始工作...
消费者开始工作...
开始生产者读取...
成功读取 3 字符...
Producer put j in buffer at 0
消费者开始工作...
Consumer consumed j from buffer at 0
开始生产者读取...
成功读取 3 字符...
Producer put f in buffer at 1
成功读取 3 字符...
Producer put o in buffer at 2
Producer put i in buffer at 3
消费者开始工作...
Consumer consumed f from buffer at 1
Producer put s in buffer at 4
Producer put k in buffer at 5
Consumer consumed o from buffer at 2
Consumer consumed i from buffer at 3
Producer put j in buffer at 6
Producer put d in buffer at 7
Consumer consumed s from buffer at 4
Consumer consumed k from buffer at 5
Consumer consumed j from buffer at 6
Consumer consumed d from buffer at 7
Producer put j in buffer at 8
Consumer consumed j from buffer at 8
成功读取 3 字符...
Producer put j in buffer at 9
Producer put s in buffer at 10
Producer put f in buffer at 11
Consumer consumed j from buffer at 9
Consumer consumed s from buffer at 10
Consumer consumed f from buffer at 11
成功读取 3 字符...
Producer put i in buffer at 12
Producer put o in buffer at 13
Producer put s in buffer at 14
成功读取 3 字符...
Producer put j in buffer at 15
Producer put o in buffer at 16
Producer put f in buffer at 17
成功读取 3 字符...
Producer put j in buffer at 18
Producer put s in buffer at 19
Producer put k in buffer at 0
成功读取 3 字符...
Producer put d in buffer at 1
Producer put j in buffer at 2
Producer put f in buffer at 3
Consumer consumed i from buffer at 12
Consumer consumed o from buffer at 13
Consumer consumed s from buffer at 14
Consumer consumed j from buffer at 15
Consumer consumed o from buffer at 16
Consumer consumed f from buffer at 17
成功读取 3 字符...
Producer put s in buffer at 4
Producer put l in buffer at 5
Producer put d in buffer at 6
Consumer consumed j from buffer at 18
Consumer consumed s from buffer at 19
Consumer consumed k from buffer at 0
Consumer consumed d from buffer at 1
Consumer consumed j from buffer at 2
Consumer consumed f from buffer at 3
成功读取 3 字符...
Producer put n in buffer at 7
Producer put f in buffer at 8
Producer put m in buffer at 9
成功读取 3 字符...
Producer put x in buffer at 10
Producer put c in buffer at 11
Producer put n in buffer at 12
成功读取 3 字符...
Producer put m in buffer at 13
Producer put b in buffer at 14
Producer put n in buffer at 15
Consumer consumed s from buffer at 4
Consumer consumed l from buffer at 5
Consumer consumed d from buffer at 6
Consumer consumed n from buffer at 7
Consumer consumed f from buffer at 8
Consumer consumed m from buffer at 9
成功读取 3 字符...
Producer put j in buffer at 16
Producer put a in buffer at 17
Producer put v in buffer at 18
成功读取 3 字符...
Producer put s in buffer at 19
Producer put j in buffer at 0
成功读取 3 字符...
Producer put h in buffer at 1
Producer put f in buffer at 2
Producer put d in buffer at 3
Producer put k in buffer at 4
Consumer consumed x from buffer at 10
Consumer consumed c from buffer at 11
Consumer consumed n from buffer at 12
Consumer consumed m from buffer at 13
Consumer consumed b from buffer at 14
Consumer consumed n from buffer at 15
成功读取 3 字符...
Producer put e in buffer at 5
Producer put r in buffer at 6
Producer put o in buffer at 7
成功读取 3 字符...
Producer put e in buffer at 8
Producer put w in buffer at 9
Producer put y in buffer at 10
成功读取 3 字符...
Producer put s in buffer at 11
Producer put f in buffer at 12
Producer put x in buffer at 13
Consumer consumed j from buffer at 16
Consumer consumed a from buffer at 17
Consumer consumed v from buffer at 18
成功读取 3 字符...
Producer put j in buffer at 14
Producer put f in buffer at 15
Producer put l in buffer at 16
Consumer consumed s from buffer at 19
Consumer consumed j from buffer at 0
Consumer consumed h from buffer at 1
成功读取 3 字符...
Producer put r in buffer at 17
Producer put o in buffer at 18
Producer put d in buffer at 19
成功读取 3 字符...
Producer put g in buffer at 0
Producer put x in buffer at 1
Consumer consumed f from buffer at 2
Consumer consumed d from buffer at 3
Consumer consumed k from buffer at 4
Producer put k in buffer at 2
Consumer consumed e from buffer at 5
Consumer consumed r from buffer at 6
Consumer consumed o from buffer at 7
成功读取 1 字符...
Producer put 
 in buffer at 3
生产者结束读取...
生产者结束读取...
Consumer consumed e from buffer at 8
Consumer consumed w from buffer at 9
Consumer consumed y from buffer at 10
Consumer consumed s from buffer at 11
Consumer consumed f from buffer at 12
Consumer consumed x from buffer at 13
生产者结束读取...
Consumer consumed j from buffer at 14
Consumer consumed f from buffer at 15
Consumer consumed l from buffer at 16
Consumer consumed r from buffer at 17
Consumer consumed o from buffer at 18
Consumer consumed d from buffer at 19
Consumer consumed g from buffer at 0
Consumer consumed x from buffer at 1
Consumer consumed k from buffer at 2
Consumer consumed 
 from buffer at 3
消费者结束工作...
消费者结束工作...
消费者结束工作...
消费者结束工作...
所有线程已结束。

三,手敲线程池

main.c

#include <stdio.h>    // 引入标准输入输出库
#include "pool.h"     // 引入自定义的线程池头文件
#include <pthread.h>  // 引入POSIX线程库
#include <unistd.h>   // 引入UNIX标准函数库
#include <stdlib.h>   // 引入标准库,用于内存分配

void taskfunc(void* arg)  // 任务函数,线程池中的线程将执行此函数
{
	int num = *(int*)arg;  // 从void*类型转换回int*,然后解引用获取传入的整数
	printf("thread %ld is working,number = %d\n", pthread_self(), num);  // 打印当前线程ID和任务处理的数字
	sleep(1);  // 让线程睡眠1秒,模拟任务执行时间
}

int main()  // 主函数
{
	// 创建线程池,参数分别为线程数量、队列最大任务数量、以及队列大小
	ThreadPool* pool = threadpool_create(3, 10, 100);
	for (int i = 0; i < 100; ++i)  // 提交100个任务到线程池
	{
		int* num = (int*)malloc(sizeof(int));  // 动态分配内存存储任务数据
		*num = i + 100;  // 初始化任务数据
		threadPoolADD(pool, taskfunc, num);  // 将任务添加到线程池
	}

	sleep(30);  // 主线程睡眠30秒,等待所有任务完成

	threadpooldelete(pool);  // 删除线程池,释放资源
	return 0;
}

pool.h 

//创建线程池并初始化
ThreadPool* threadpool_create(int min, int max, int queuesize);
//销毁线程池
int threadpooldelete(ThreadPool* pool);


//给线程池添加任务
void threadPoolADD(ThreadPool* pool, void(*func)(void*), void* arg);

//获取线程池中工作的线程个数
int threadpoolbusynum(ThreadPool* pool);

//获取线程池中活着的线程的个数
int threadpoolalivenum(ThreadPool* pool);


void* worker(void* arg);
void* manager(void* arg);
void threadExit(ThreadPool* pool);

//任务结构体
typedef struct Task
{
    void (*function)(void* arg); // 函数指针,指向任务函数
    void* arg;                   // 参数,传递给任务函数
} Task;

//线程池结构体
struct ThreadPool
{
    Task* taskQ;                   // 任务队列数组,存储待执行的任务
    int queueCapacity;             // 队列的最大容量
    int queueSize;                 // 当前队列中的任务数量
    int queueFront;                // 队列头部索引,指向待取出任务
    int queueRear;                 // 队列尾部索引,指向新添加任务的位置

    pthread_t managerID;           // 管理者线程ID
    pthread_t* threadIDs;          // 工作线程ID数组

    int minNum;                    // 最小线程数量
    int maxNum;                    // 最大线程数量
    int busyNum;                   // 忙碌的线程数量
    int liveNum;                   // 存活的线程数量
    int exitNum;                   // 需要退出的线程数量

    pthread_mutex_t mutexpool;     // 互斥锁,用于保护线程池资源
    pthread_mutex_t mutexBusy;     // 互斥锁,用于保护busyNum变量
    pthread_cond_t full;           // 条件变量,当任务队列满时阻塞添加任务的线程
    pthread_cond_t empty;          // 条件变量,当任务队列空时阻塞取任务的线程
    int shutdown;                  // 控制线程池是否关闭的标志
};
ThreadPool* threadpool_create(int min, int max, int queuesize)
{
    ThreadPool* pool = (ThreadPool*)malloc(sizeof(ThreadPool)); // 分配内存给线程池结构体

    if (pool == NULL) // 内存分配失败处理
    {
        printf("malloc threadpool fail...\n");
        return NULL;
    }

    pool->threadIDs = (pthread_t*)malloc(sizeof(pthread_t) * max); // 分配内存给线程ID数组
    if (pool->threadIDs == NULL) // 内存分配失败处理
    {
        printf("malloc threadIDs fail...\n");
        free(pool);
        return NULL;
    }

    memset(pool->threadIDs, 0, sizeof(pthread_t) * max); // 初始化线程ID数组
    pool->taskQ = (Task*)malloc(sizeof(Task) * queuesize); // 分配内存给任务队列
    if (pool->taskQ == NULL) // 内存分配失败处理
    {
        printf("malloc task queue fail...\n");
        free(pool->threadIDs);
        free(pool);
        return NULL;
    }

    pool->minNum = min; // 设置最小线程数
    pool->maxNum = max; // 设置最大线程数
    pool->busyNum = 0;  // 初始化忙碌线程数
    pool->liveNum = min;// 初始化存活线程数
    pool->exitNum = 0;  // 初始化退出线程数
    pool->queueCapacity = queuesize; // 设置任务队列容量
    pool->queueSize = 0; // 初始化任务队列大小
    pool->queueFront = 0; // 初始化队列头部索引
    pool->queueRear = 0;  // 初始化队列尾部索引
    pool->shutdown = 0;   // 初始化关闭标志

    if (pthread_mutex_init(&pool->mutexpool, NULL) != 0 || // 初始化互斥锁
        pthread_mutex_init(&pool->mutexBusy, NULL) != 0 || // 初始化互斥锁
        pthread_cond_init(&pool->empty, NULL) != 0 ||      // 初始化条件变量
        pthread_cond_init(&pool->full, NULL) != 0)         // 初始化条件变量
    {
        printf("mutex or condition init fail...\n");
        free(pool->taskQ);
        free(pool->threadIDs);
        free(pool);
        return NULL;
    }

    // 创建管理者线程
    if (pthread_create(&pool->managerID, NULL, manager, pool) != 0)
    {
        printf("Failed to create manager thread.\n");
        threadpooldelete(pool); // 如果创建失败,调用销毁函数
        return NULL;
    }

    // 创建工作线程
    for (int i = 0; i < min; ++i)
    {
        if (pthread_create(&pool->threadIDs[i], NULL, worker, pool) != 0)
        {
            printf("Failed to create worker thread %d.\n", i);
            pool->liveNum--; // 如果创建失败,减少存活线程计数
        }
    }

    return pool; // 返回创建的线程池指针
}
int threadpooldelete(ThreadPool* pool)
{
    if (pool == NULL) // 检查线程池指针是否为空
    {
        return -1; // 如果为空,返回错误码
    }
    pool->shutdown = 1; // 设置线程池的关闭标志为1

    // 阻塞等待管理者线程结束
    pthread_join(pool->managerID, NULL);

    // 唤醒所有可能阻塞在空条件变量上的工作线程
    for (int i = 0; i < pool->liveNum; ++i)
    {
        pthread_cond_signal(&pool->empty);
    }

    // 等待所有工作线程结束
    for (int i = 0; i < pool->liveNum; i++)
    {
        if (pool->threadIDs[i] != 0) // 检查线程ID是否有效
        {
            pthread_join(pool->threadIDs[i], NULL); // 阻塞等待线程结束
        }
    }

    // 释放内存资源
    if (pool->threadIDs)
    {
        free(pool->threadIDs); // 释放线程ID数组
    }
    
    if (pool->taskQ)
    {
        free(pool->taskQ); // 释放任务队列
    }

    // 销毁互斥锁和条件变量
    pthread_mutex_destroy(&pool->mutexpool);
    pthread_mutex_destroy(&pool->mutexBusy);
    pthread_cond_destroy(&pool->empty);
    pthread_cond_destroy(&pool->full);

    free(pool); // 释放线程池结构体内存
    pool = NULL; // 将线程池指针设置为NULL
    printf("Thread pool is deleted successfully.\n");
    return 0; // 返回成功码
}
void threadPoolADD(ThreadPool* pool, void(*func)(void*), void* arg)
{
    pthread_mutex_lock(&pool->mutexpool); // 锁定线程池以安全修改
    while (pool->queueSize == pool->queueCapacity && !pool->shutdown) // 如果任务队列满且线程池未关闭
    {
        pthread_cond_wait(&pool->full, &pool->mutexpool); // 阻塞,等待有空闲空间
    }

    if (pool->shutdown) // 如果线程池正在关闭
    {
        pthread_mutex_unlock(&pool->mutexpool); // 解锁后直接返回
        return;
    }

    // 添加任务到队列
    pool->taskQ[pool->queueRear].function = func; // 设置任务函数
    pool->taskQ[pool->queueRear].arg = arg; // 设置任务参数
    pool->queueRear = (pool->queueRear + 1) % pool->queueCapacity; // 循环队列,移动尾指针
    pool->queueSize++; // 增加队列中的任务数量
    pthread_cond_signal(&pool->empty); // 通知工作线程有新任务

    pthread_mutex_unlock(&pool->mutexpool); // 解锁线程池
}
void* worker(void* arg)
{
    ThreadPool* pool = (ThreadPool*)arg; // 获取线程池对象的指针

    while (1) // 永久循环,直到线程池关闭
    {
        pthread_mutex_lock(&pool->mutexpool); // 锁定线程池
        while (pool->queueSize == 0 && !pool->shutdown) // 当队列空且线程池未关闭时
        {
            pthread_cond_wait(&pool->empty, &pool->mutexpool); // 等待新任务
        }

        if (pool->shutdown) // 如果线程池关闭
        {
            pthread_mutex_unlock(&pool->mutexpool); // 解锁
            threadExit(pool); // 退出线程
        }

        // 取出一个任务
        Task task = pool->taskQ[pool->queueFront];
        pool->queueFront = (pool->queueFront + 1) % pool->queueCapacity; // 更新头指针
        pool->queueSize--; // 减少队列中的任务数
        pthread_cond_signal(&pool->full); // 通知可以添加新任务
        pthread_mutex_unlock(&pool->mutexpool); // 解锁

        printf("thread %ld start working...\n", pthread_self()); // 打印开始工作的信息
        task.function(task.arg); // 执行任务
        free(task.arg); // 释放任务参数内存
        printf("thread %ld end working...\n", pthread_self()); // 打印结束工作的信息
    }

    return NULL; // 返回NULL,线程结束
}
void* manager(void* arg)
{
    ThreadPool* pool = (ThreadPool*)arg; // 获取线程池对象的指针

    while (!pool->shutdown) // 当线程池没有关闭时循环
    {
        sleep(3); // 每3秒运行一次管理任务

        pthread_mutex_lock(&pool->mutexpool); // 锁定线程池
        int queueSize = pool->queueSize; // 获取当前队列大小
        int liveNum = pool->liveNum; // 获取当前活跃线程数
        pthread_mutex_unlock(&pool->mutexpool); // 解锁线程池

        pthread_mutex_lock(&pool->mutexBusy); // 锁定忙碌线程数
        int busyNum = pool->busyNum; // 获取当前忙碌线程数
        pthread_mutex_unlock(&pool->mutexBusy); // 解锁忙碌线程数锁

        // 添加线程的条件:任务数大于活跃线程数且活跃线程数小于最大线程数
        if (queueSize > liveNum && liveNum < pool->maxNum)
        {
            pthread_mutex_lock(&pool->mutexpool); // 锁定线程池
            int counter = 0;
            for (int i = 0; i < pool->maxNum && counter < NUMBER && pool->liveNum < pool->maxNum; ++i)
            {
                if (pool->threadIDs[i] == 0) // 如果线程ID位置为空,可以创建新线程
                {
                    if (pthread_create(&pool->threadIDs[i], NULL, worker, pool) != 0) {
                        printf("Failed to create a new worker thread\n");
                        continue;  // 如果创建失败,跳过当前循环
                    }
                    counter++; // 成功创建线程,计数增加
                    pool->liveNum++; // 活跃线程数增加
                }
            }
            pthread_mutex_unlock(&pool->mutexpool); // 解锁线程池
        }

        // 销毁线程的条件:忙线程数的两倍小于活跃线程数,且活跃线程数大于最小线程数
        if (busyNum * 2 < liveNum && liveNum > pool->minNum)
        {
            pthread_mutex_lock(&pool->mutexpool); // 锁定线程池
            pool->exitNum = NUMBER; // 设置退出线程数
            pthread_mutex_unlock(&pool->mutexpool); // 解锁线程池

            for (int i = 0; i < NUMBER; ++i)
            {
                pthread_cond_signal(&pool->empty); // 发信号让线程退出
            }
        }
    }

    return NULL; // 返回NULL,线程结束
}
void threadExit(ThreadPool* pool)
{
    pthread_t tid = pthread_self(); // 获取当前线程的ID
    for (int i = 0; i < pool->maxNum; ++i)
    {
        if (pool->threadIDs[i] == tid) // 寻找当前线程在数组中的位置
        {
            pool->threadIDs[i] = 0; // 将该位置清零,表示线程结束
            printf("threadExit()called,%ld exiting...\n", tid);
            break; // 退出循环
        }
    }
    pthread_exit(NULL); // 使线程退出
}
hui@hui-virtual-machine:~/projects/pool/bin/x64/Debug$ ./pool.out 
thread 140310486038272 start working...
thread 140310486038272 is working,number = 100
thread 140310494430976 start working...
thread 140310494430976 is working,number = 101
thread 140310502823680 start working...
thread 140310502823680 is working,number = 102
thread 140310486038272 end working...
thread 140310486038272 start working...
thread 140310486038272 is working,number = 103
thread 140310494430976 end working...
thread 140310494430976 start working...
thread 140310494430976 is working,number = 104
thread 140310502823680 end working...
thread 140310502823680 start working...
thread 140310502823680 is working,number = 105
thread 140310486038272 end working...
thread 140310486038272 start working...
thread 140310486038272 is working,number = 106
thread 140310494430976 end working...
thread 140310502823680 end working...
thread 140310502823680 start working...
thread 140310502823680 is working,number = 108
thread 140310494430976 start working...
thread 140310494430976 is working,number = 107
thread 140310264932096 start working...
thread 140310264932096 is working,number = 109
thread 140310273324800 start working...
thread 140310273324800 is working,number = 110
thread 140310486038272 end working...
thread 140310486038272 start working...
thread 140310486038272 is working,number = 111
thread 140310502823680 end working...
thread 140310502823680 start working...
thread 140310502823680 is working,number = 112
thread 140310494430976 end working...
thread 140310494430976 start working...
thread 140310494430976 is working,number = 113
thread 140310264932096 end working...
thread 140310264932096 start working...
thread 140310264932096 is working,number = 114
thread 140310273324800 end working...
thread 140310273324800 start working...
thread 140310273324800 is working,number = 115
thread 140310486038272 end working...
thread 140310486038272 start working...
thread 140310486038272 is working,number = 116
thread 140310502823680 end working...
thread 140310502823680 start working...
thread 140310502823680 is working,number = 117
thread 140310494430976 end working...
thread 140310494430976 start working...
thread 140310494430976 is working,number = 118
thread 140310264932096 end working...
thread 140310264932096 start working...
thread 140310264932096 is working,number = 119
thread 140310273324800 end working...
thread 140310273324800 start working...
thread 140310273324800 is working,number = 120
thread 140310486038272 end working...
thread 140310486038272 start working...
thread 140310486038272 is working,number = 121
thread 140310502823680 end working...
thread 140310502823680 start working...
thread 140310502823680 is working,number = 122
thread 140310494430976 end working...
thread 140310494430976 start working...
thread 140310494430976 is working,number = 123
thread 140310248146688 start working...
thread 140310248146688 is working,number = 124
thread 140310256539392 start working...
thread 140310256539392 is working,number = 125
thread 140310273324800 end working...
thread 140310273324800 start working...
thread 140310273324800 is working,number = 126
thread 140310264932096 end working...
thread 140310264932096 start working...
thread 140310264932096 is working,number = 127
thread 140310486038272 end working...
thread 140310502823680 end working...
thread 140310502823680 start working...
thread 140310486038272 start working...
thread 140310486038272 is working,number = 128
thread 140310502823680 is working,number = 129
thread 140310494430976 end working...
thread 140310494430976 start working...
thread 140310494430976 is working,number = 130
thread 140310256539392 end working...
thread 140310256539392 start working...
thread 140310256539392 is working,number = 131
thread 140310248146688 end working...
thread 140310248146688 start working...
thread 140310248146688 is working,number = 132
thread 140310273324800 end working...
thread 140310273324800 start working...
thread 140310273324800 is working,number = 133
thread 140310264932096 end working...
thread 140310264932096 start working...
thread 140310264932096 is working,number = 134
thread 140310486038272 end working...
thread 140310486038272 start working...
thread 140310486038272 is working,number = 135
thread 140310502823680 end working...
thread 140310502823680 start working...
thread 140310502823680 is working,number = 136
thread 140310494430976 end working...
thread 140310494430976 start working...
thread 140310494430976 is working,number = 137
thread 140310256539392 end working...
thread 140310256539392 start working...
thread 140310256539392 is working,number = 138
thread 140310248146688 end working...
thread 140310248146688 start working...
thread 140310248146688 is working,number = 139
thread 140310273324800 end working...
thread 140310273324800 start working...
thread 140310273324800 is working,number = 140
thread 140310264932096 end working...
thread 140310264932096 start working...
thread 140310264932096 is working,number = 141
thread 140310486038272 end working...
thread 140310486038272 start working...
thread 140310486038272 is working,number = 142
thread 140310502823680 end working...
thread 140310502823680 start working...
thread 140310502823680 is working,number = 143
thread 140310494430976 end working...
thread 140310494430976 start working...
thread 140310494430976 is working,number = 144
thread 140310239753984 start working...
thread 140310239753984 is working,number = 145
thread 140310231361280 start working...
thread 140310231361280 is working,number = 146
thread 140310256539392 end working...
thread 140310256539392 start working...
thread 140310256539392 is working,number = 147
thread 140310248146688 end working...
thread 140310248146688 start working...
thread 140310248146688 is working,number = 148
thread 140310273324800 end working...
thread 140310273324800 start working...
thread 140310273324800 is working,number = 149
thread 140310264932096 end working...
thread 140310264932096 start working...
thread 140310264932096 is working,number = 150
thread 140310486038272 end working...
thread 140310486038272 start working...
thread 140310486038272 is working,number = 151
thread 140310502823680 end working...
thread 140310502823680 start working...
thread 140310502823680 is working,number = 152
thread 140310494430976 end working...
thread 140310494430976 start working...
thread 140310494430976 is working,number = 153
thread 140310239753984 end working...
thread 140310239753984 start working...
thread 140310239753984 is working,number = 154
thread 140310231361280 end working...
thread 140310231361280 start working...
thread 140310231361280 is working,number = 155
thread 140310256539392 end working...
thread 140310256539392 start working...
thread 140310256539392 is working,number = 156
thread 140310248146688 end working...
thread 140310248146688 start working...
thread 140310248146688 is working,number = 157
thread 140310273324800 end working...
thread 140310273324800 start working...
thread 140310273324800 is working,number = 158
thread 140310264932096 end working...
thread 140310264932096 start working...
thread 140310264932096 is working,number = 159
thread 140310486038272 end working...
thread 140310486038272 start working...
thread 140310486038272 is working,number = 160
thread 140310502823680 end working...
thread 140310502823680 start working...
thread 140310502823680 is working,number = 161
thread 140310494430976 end working...
thread 140310494430976 start working...
thread 140310494430976 is working,number = 162
thread 140310248146688 end working...
thread 140310248146688 start working...
thread 140310248146688 is working,number = 163
thread 140310231361280 end working...
thread 140310231361280 start working...
thread 140310231361280 is working,number = 164
thread 140310239753984 end working...
thread 140310239753984 start working...
thread 140310239753984 is working,number = 165
thread 140310256539392 end working...
thread 140310256539392 start working...
thread 140310256539392 is working,number = 166
thread 140310273324800 end working...
thread 140310273324800 start working...
thread 140310273324800 is working,number = 167
thread 140310264932096 end working...
thread 140310264932096 start working...
thread 140310264932096 is working,number = 168
thread 140310502823680 end working...
thread 140310502823680 start working...
thread 140310502823680 is working,number = 169
thread 140310486038272 end working...
thread 140310486038272 start working...
thread 140310486038272 is working,number = 170
thread 140310494430976 end working...
thread 140310494430976 start working...
thread 140310494430976 is working,number = 171
thread 140310222968576 start working...
thread 140310222968576 is working,number = 172
thread 140310248146688 end working...
thread 140310248146688 start working...
thread 140310248146688 is working,number = 173
thread 140310239753984 end working...
thread 140310239753984 start working...
thread 140310239753984 is working,number = 174
thread 140310231361280 end working...
thread 140310231361280 start working...
thread 140310231361280 is working,number = 175
thread 140310273324800 end working...
thread 140310273324800 start working...
thread 140310273324800 is working,number = 176
thread 140310256539392 end working...
thread 140310256539392 start working...
thread 140310256539392 is working,number = 177
thread 140310264932096 end working...
thread 140310264932096 start working...
thread 140310264932096 is working,number = 178
thread 140310502823680 end working...
thread 140310502823680 start working...
thread 140310502823680 is working,number = 179
thread 140310486038272 end working...
thread 140310486038272 start working...
thread 140310486038272 is working,number = 180
thread 140310494430976 end working...
thread 140310494430976 start working...
thread 140310494430976 is working,number = 181
thread 140310222968576 end working...
thread 140310222968576 start working...
thread 140310222968576 is working,number = 182
thread 140310239753984 end working...
thread 140310239753984 start working...
thread 140310239753984 is working,number = 183
thread 140310256539392 end working...
thread 140310256539392 start working...
thread 140310256539392 is working,number = 184
thread 140310248146688 end working...
thread 140310248146688 start working...
thread 140310248146688 is working,number = 185
thread 140310231361280 end working...
thread 140310231361280 start working...
thread 140310231361280 is working,number = 186
thread 140310273324800 end working...
thread 140310273324800 start working...
thread 140310273324800 is working,number = 187
thread 140310264932096 end working...
thread 140310264932096 start working...
thread 140310264932096 is working,number = 188
thread 140310486038272 end working...
thread 140310486038272 start working...
thread 140310486038272 is working,number = 189
thread 140310502823680 end working...
thread 140310502823680 start working...
thread 140310502823680 is working,number = 190
thread 140310494430976 end working...
thread 140310494430976 start working...
thread 140310494430976 is working,number = 191
thread 140310222968576 end working...
thread 140310222968576 start working...
thread 140310222968576 is working,number = 192
thread 140310239753984 end working...
thread 140310239753984 start working...
thread 140310239753984 is working,number = 193
thread 140310256539392 end working...
thread 140310256539392 start working...
thread 140310256539392 is working,number = 194
thread 140310273324800 end working...
thread 140310273324800 start working...
thread 140310273324800 is working,number = 195
thread 140310248146688 end working...
thread 140310248146688 start working...
thread 140310248146688 is working,number = 196
thread 140310231361280 end working...
thread 140310231361280 start working...
thread 140310231361280 is working,number = 197
thread 140310264932096 end working...
thread 140310264932096 start working...
thread 140310264932096 is working,number = 198
thread 140310486038272 end working...
thread 140310486038272 start working...
thread 140310486038272 is working,number = 199
thread 140310502823680 end working...
thread 140310494430976 end working...
thread 140310222968576 end working...
thread 140310239753984 end working...
thread 140310256539392 end working...
thread 140310273324800 end working...
thread 140310248146688 end working...
thread 140310231361280 end working...
thread 140310264932096 end working...
thread 140310486038272 end working...
threadExit()called,140310502823680 exiting...
threadExit()called,140310494430976 exiting...
threadExit()called,140310222968576 exiting...
threadExit()called,140310239753984 exiting...
threadExit()called,140310273324800 exiting...
threadExit()called,140310256539392 exiting...
threadExit()called,140310248146688 exiting...
threadExit()called,140310264932096 exiting...
threadExit()called,140310486038272 exiting...
threadExit()called,140310231361280 exiting...
Thread pool is deleted successfully.
hui@hui-virtual-machine:~/projects/pool/bin/x64/Debug$ 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值