当前位置: 首页 > news >正文

【C语言】多进程/多线程

【C语言】多进程/多线程

  • 参考链接
  • 多进程/多线程服务器
    • 1. 多进程服务器
    • 2. 多线程服务器
  • 结语
  • 参考链接

在这里插入图片描述

参考链接

c 中文网
菜鸟 c

多进程/多线程服务器

  多进程和多线程是常用的并发编程技术。它们都允许程序同时执行多个任务,提高了系统的资源利用率和程序的运行效率。

1. 多进程服务器

  多进程是指在操作系统中同时运行多个独立的进程。每个进程都有自己独立的地址空间和资源,进程间的通信通过操作系统提供的进程间通信机制进行。多进程可以充分利用多核处理器的优势,提高系统的整体性能。然而,进程间的切换会引入较大的开销,并且需要较高的内存开销。

  服务器使用 fork 创建子进程来和客户端进行通信,父进程负责取出连接请求。

#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <strings.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <arpa/inet.h>

// 信号处理函数
void waitchild(int signo)
{
    pid_t wpid;
    while (1)
    {
        wpid = waitpid(-1, NULL, WNOHANG);
        if (wpid > 0)
        {
            printf("child exit, wpid==[%d]\n", wpid);
        }
        else if (wpid == 0 || wpid == -1)
        {
            break;
        }
    }
}

int main()
{
    // 阻塞SIGCHLD信号
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGCHLD);
    sigprocmask(SIG_BLOCK, &mask, NULL);
    int sigbol = 1;

    int sfd = socket(AF_INET, SOCK_STREAM, 0);

    // 设置端口复用
    int opt = 1;
    setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));

    struct sockaddr_in soaddr;
    bzero(&soaddr, sizeof(soaddr));

    soaddr.sin_family = AF_INET;
    soaddr.sin_port = htons(9999);
    soaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    bind(sfd, (struct sockaddr *)&soaddr, sizeof(soaddr));

    //监听-listen
    listen(sfd, 128);

    struct sockaddr_in clientsocket;
    socklen_t clilen;

    char sIP[16];

    while (1)
    {
        clilen = sizeof(clientsocket);
        bzero(&clientsocket, clilen);

        int cfd = accept(sfd, (struct sockaddr *)&clientsocket, &clilen);

        /* */
        int pid = fork();
        if (pid == 0)
        {
            // 子进程
            close(sfd);
            char buff[64];
            printf("current pid is [%d],father is [%d]\n", getpid(), getppid());
            while (1)
            {
                memset(buff, 0x00, sizeof(buff));
                int n = read(cfd, buff, sizeof(buff));
                if (n == 0)
                {
                    return 0;
                }
                else if (n < 0)
                {
                    perror("child read error");
                    return -1;
                }
                printf("child [%d] recv data from [%s:%d]:[%s]\n", getpid(), inet_ntop(AF_INET, &clientsocket.sin_addr.s_addr, sIP, sizeof(sIP)), ntohs(clientsocket.sin_port), buff);
                for (int i = 0; i < n; i++)
                {
                    buff[i] = toupper(buff[i]);
                }
                n = Write(cfd, buff, n);
                if (n <= 0)
                {
                    perror("child write error");
                    return -1;
                }
            }
        }
        else if (pid > 0)
        {
            // 父进程
            close(cfd);

            //假如是初次fork子进程,那么才注册信号处理函数
            if (sigbol == 1)
            {
                sigbol = 0;
                // 注册SIGCHLD信号处理函数
                struct sigaction act;
                act.sa_handler = waitchild;
                act.sa_flags = 0;
                sigemptyset(&act.sa_mask);
                sigaction(SIGCHLD, &act, NULL);

                // 解除对SIGCHLD信号的阻塞
                sigprocmask(SIG_UNBLOCK, &mask, NULL);
            }
            //循环等待下一个连接请求的到来
            continue;
        }
        else
        {
            perror("fork error");
            close(sfd);
            return -1;
        }


    }

    return 0;
}

2. 多线程服务器

  多线程是指在同一个进程中同时运行多个独立的线程。与进程不同,线程共享同一个地址空间和资源,可以通过共享内存等方式进行线程间的通信。多线程可以减少线程间的切换开销和内存开销,提高系统的响应速度和资源利用率。然而,多线程编程需要考虑线程安全问题,需要使用线程同步技术来保证共享资源的正确访问。

  主线程创建子线程,用子进程和客户端通信。

#include <arpa/inet.h>
#include <pthread.h>
#include <strings.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <unistd.h>

typedef struct info
{
    int cfd; // 若为-1表示可用, 大于0表示已被占用
    int idx;
    pthread_t thread;          // 由pthread_create 返回
    struct sockaddr_in client; // 由accept 返回
} INFO;

INFO thInfo[1024];

void initThreadArr()
{
    for (int i = 0; i < 1024; i++)
    {
        bzero(&thInfo[i],sizeof(thInfo[i]));
        thInfo[i].cfd = -1;
    }
}

int findIndex()
{
    int i;
    for (i = 0; i < 1024; i++)
    {
        if (thInfo[i].cfd == -1)
        {
            return i;
        }
    }
    //if (i == 1024)
    //{
    //    return -1;
    //}
    return -1;
}

void *threadFunc(void *arg)
{
    INFO *curthread = (INFO *)arg;
    char sIP[16];
    printf("current thread id [%ld],arr index is [%d],cfd is [%d],client ip is [%s:%d]\n", pthread_self(), curthread->idx, curthread->cfd, inet_ntop(AF_INET, &curthread->client.sin_addr.s_addr, sIP, sizeof(sIP)), ntohs(curthread->client.sin_port));
    char buff[64];
    while (1)
    {
        memset(buff, 0x00, sizeof(buff));
        int n = read(curthread->cfd, buff, sizeof(buff));
        if (n == 0)
        {
            bzero(&thInfo[curthread->idx],sizeof(thInfo[curthread->idx]));
            thInfo[thInfo->idx].cfd = -1;
            return 0;
        }
        else if (n < 0)
        {
            bzero(&thInfo[curthread->idx],sizeof(thInfo[curthread->idx]));
            thInfo[thInfo->idx].cfd = -1;
            perror("child read error");
            return 0;
        }

        printf("child thread [%ld] recv data from [%s:%d]:[%s]\n", pthread_self(), inet_ntop(AF_INET, &curthread->client.sin_addr.s_addr, sIP, sizeof(sIP)), ntohs(curthread->client.sin_port), buff);
        for (int i = 0; i < n; i++)
        {
            buff[i] = toupper(buff[i]);
        }
        n = write(curthread->cfd, buff, n);
        if (n <= 0)
        {
            bzero(&thInfo[curthread->idx],sizeof(thInfo[curthread->idx]));
            thInfo[thInfo->idx].cfd = -1;
            perror("child write error");
            return 0;
        }
    }
}

int main()
{

    initThreadArr();

    int sfd = socket(AF_INET, SOCK_STREAM, 0);

    // 设置端口复用
    int opt = 1;
    setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));

    struct sockaddr_in soaddr;
    bzero(&soaddr, sizeof(soaddr));

    soaddr.sin_family = AF_INET;
    soaddr.sin_port = htons(9999);
    soaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    bind(sfd, (struct sockaddr *)&soaddr, sizeof(soaddr));

    // 监听-listen
    listen(sfd, 128);

    struct sockaddr_in clientsocket;
    socklen_t clilen;

    int cfd;
    int index;
    int ret;

    while (1)
    {
        index = -1;
        clilen = sizeof(clientsocket);
        bzero(&clientsocket, clilen);

        cfd = accept(sfd, (struct sockaddr *)&clientsocket, &clilen);
        // 从线程数组中找一个可以用的
        index = findIndex();
        thInfo[index].idx = index;
        thInfo[index].client = clientsocket;
        thInfo[index].cfd = cfd;

        // 创建线程
        ret = pthread_create(&thInfo[index].thread, NULL, threadFunc, &thInfo[index]);

        if (ret != 0)
        {
            printf("create thread error:[%s]\n", strerror(ret));
            exit(-1);
        }

        // 设置子线程为分离属性
        pthread_detach(thInfo[index].thread);
    }

    Close(sfd);

    return 0;
}

结语

  多进程和多线程的选择取决于具体的应用场景。如果任务之间需要较高的隔离度,或者需要充分利用多核处理器的优势,可以选择多进程。如果任务之间需要较低的切换开销和内存开销,或者需要提高系统的响应速度和资源利用率,可以选择多线程。

参考链接

c 中文网
菜鸟 c

相关文章:

  • DeepSeek-R1 现已作为全托管无服务器模型在 Amazon Bedrock上线。
  • 反向 SSH 隧道技术实现内网穿透
  • 数据库误更新操作 如何回滚
  • VMware安装ubuntu22.04.5 server
  • Java并发编程面试汇总
  • Python学习第二十三天
  • 全面了解 Cookies、Session 和 Token
  • 【Java语言】学习笔记-08面向对象【中级】包、访问修饰符、封装、继承、多态、Super、Override(重写)、Object、断点调试等细节详解(上)
  • 6.1、认证技术基础与原理
  • [unity 点击事件] 区域响应点击事件,排除子节点区域,Raycast Target 应用
  • 埋点数据采集方案
  • 14、Python 枚举与类型注解进阶
  • 蓝桥云客 数字接龙
  • JAVA 单调栈习题解析
  • 入剖析 Android Compose 框架的关键帧动画(keyframes、Animatable)(二十三)
  • 蓝耘云平台免费 Token 获取攻略:让创作成本直线下降 - 极致优化版
  • Maven 构建配置文件
  • 工作效率upup
  • Ubuntu20.04.6系统根目录扩容
  • JWT 鉴权常见知识点及参考答案
  • “五一”假期国铁集团计划日均开行旅客列车超1.2万列
  • 高速变道致连环车祸,白车“骑”隔离栏压住另一车,交警回应
  • 体坛联播|曼联一只脚迈进欧联杯决赛,赵心童4比4奥沙利文
  • 韩国经济副总理崔相穆宣布辞职
  • 魔都眼|石库门里看车展,五一来张园体验城市“漫时光”
  • 解放日报:浦东夯实“热带雨林”式科创生态