《TCP/IP网络编程》阅读笔记--多线程服务器端的实现

news2025/1/22 6:24:35

1--多线程的优点

多进程服务器的缺点:

        ① 创建进程的过程会带来一定的开销;

        ② 为了完成进程间的数据交换,需要特殊的 IPC 技术;

        ③ 进程间的上下文切换是创建进程时的最大开销;

多线程的优点:

        ① 线程的创建和上下文切换比进程的创建和上下文切换更快;

        ② 线程间交换数据时无需特殊技术;

2--进程和线程的差异

        每个进程拥有独立的内存空间,拥有自己的数据区、堆区域和栈区域;

        每个线程只拥有自己的栈区域,线程间共享数据区和堆区域;因此线程间上下文切换时不需要切换数据区和堆,可以利用数据区和堆区域交换数据;

        

        进程:在操作系统构成单独执行流的单位;

        线程:在进程构成单独执行流的单位;

        进程是在操作系统内部生成多个执行流,线程就是在同一进程内部创建多条执行流;

3--线程创建

#include <pthread.h>
int pthread_create(pthread_t* restrict thread, const pthread_attr_t* restrict attr, void* (* start_routine)(void*), void* restrict arg);
// 成功时返回 0,失败时返回其他值
// thread 表示保存新创建线程 ID 的变量地址值
// attr 表示用于传递线程属性的参数,传递 NULL 时表示创建默认属性的线程
// start_routine 表示线程的入口函数
// arg 表示传递给线程入口函数的参数
// gcc thread1.c -o thread1 -lpthread
// ./thread1

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

void* thread_main(void* arg){ // 线程入口函数
    int i;
    int cnt = *((int*)arg);
    for(i = 0; i < cnt; i++){
        sleep(1);
        puts("running thread");
    }
    return NULL;
}

int main(int argc, char* argv[]){
    pthread_t t_id;
    int thread_param = 5;
    if(pthread_create(&t_id, NULL, thread_main, (void*)&thread_param) != 0){ // 创建线程
        puts("pthread_create() error");
        return -1;
    }
    sleep(10);
    puts("end of main");
    return 0;
}

4--线程使用

        调用 pthread_join(ID) 可以使进程或线程进入等待状态,直到 ID 对应的线程终止为止;

#include <pthread.h>
int pthread_join(pthread_t thread, void** status);
// 成功时返回0,失败时返回其他值
// thread 表示线程ID,只有该线程终止后才会从函数返回
// status 表示保存线程返回值的指针变量地址值 
// gcc thread2.c -o thread2 -lpthread
// ./thread2

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

void* thread_main(void *arg){
    int i;
    int cnt = *((int*)arg);
    char* msg = (char*)malloc(sizeof(char)*50);
    strcpy(msg, "Hello, I'm thread~ \n");

    for(i = 0; i < cnt; i++){
        sleep(1);
        puts("running thread");
    }
    return (void*)msg;
}

int main(int argc, char* argv[]){
    pthread_t t_id;
    int thread_param = 5;
    void* thr_ret;

    // 创建线程
    if(pthread_create(&t_id, NULL, thread_main, (void*)&thread_param) != 0){
        puts("pthread_create() error");
        return -1;
    }
    // 阻塞,等待线程返回
    if(pthread_join(t_id, &thr_ret) != 0){
        puts("pthread_join() error");
        return -1;
    }

    // 打印线程返回值
    printf("Thread return message: %s \n", (char*)thr_ret);
    free(thr_ret);
    return 0;
}

5--线程安全问题

        多个线程同时调用函数执行临界区代码时,会出现问题;

        根据临界区是否引起问题,函数可分为:线程安全函数和非线程安全函数;

        线程安全函数被多个线程同时调用时不会引发问题,非线程安全函数被同时调用时会引发问题;

        以下代码展示了多个线程同时访问临界区代码操作全局变量时会出现意向不到的问题;

// gcc thread4.c -D_REENTRANT -o thread4 -lpthread
// ./thread4

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#define NUM_THREAD 100

long long num = 0;

void* thread_inc(void* arg){
    int i;
    for(i = 0; i < 50000000; i++){
        num += 1;
    }
    return 0;
}

void* thread_des(void* arg){
    int i;
    for(i = 0; i < 50000000; i++){
        num -= 1;
    }
    return 0;
}

int main(int argc, char* argv[]){
    pthread_t thread_id[NUM_THREAD];
    int i;

    printf("sizeof long long: %ld \n", sizeof(long long));
    for(i = 0; i < NUM_THREAD; i++){
        // 各创建50个线程,分别执行对全局变量 num 的加减操作
        if(i%2){
            pthread_create(&(thread_id[i]), NULL, thread_inc, NULL);
        }
        else{
            pthread_create(&(thread_id[i]), NULL, thread_des, NULL);
        }
    }

    for(i = 0; i < NUM_THREAD; i++){
        pthread_join(thread_id[i], NULL);
    }

    printf("result: %lld \n", num);
    return 0;
}

        正常结果应为0,但实际结果并不是;这就是多线程同时访问临界区,会出现数据竞争等的问题;

        线程访问变量 num 时应阻止其他线程访问,直到一个线程完成运算,这就是同步(Synchronization);线程同步用于解决线程访问顺序引发的问题;

6--互斥量

        互斥量表示不允许多个线程同时访问,主要用于解决线程同步访问的问题;

#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr);
int pthread_mutex_destroy(pthread_mutex_t* mutex);
// 成功时返回 0,失败时返回其他值
// mutex 表示创建和销毁互斥量时传递保存和销毁互斥量的变量地址值
// attr 传递即将创建的互斥量属性,没有特别需要指定的属性时传递 NULL

int pthread_mutex_lock(pthread_mutex_t* mutex); // 上锁
int pthread_mutex_unlock(pthread_mutex_t* mutex); // 解锁
// 成功时返回 0,失败时返回其他值

pthread_mutex_t mutex;
pthread_mutex_lock(&mutex);
// 临界区开始
// ...
// 临界区结束
pthread_mutex_unlock(&mutex);

7--信号量

        利用二进制信号量完成控制线程程序为中心的同步方法;

#include <semaphore.h>
int sem_init(sem_t* sem, int pshared, unsigned int value);
int sem_destroy(sem_t* sem);
// 成功时返回 0,失败时返回其他值
// sem 表示信号量的变量地址值
// pshared 传递其他值时,创建可由多个进程共享的信号量;传递 0 时,创建只允许一个进程内部使用的信号量
// value 表示指定新创建的信号量的初始值

int sem_post(sem_t* sem); // 信号量增加1
int sem_wait(sem_t* sem); // 信号量减少1
// 成功时返回 0,失败时返回其他值

sem_wait(&sem); // 信号量变为0
// 临界区的开始
// ...
// 临界区的结束
sem_post(&sem); // 信号量变为1

8--线程销毁

线程销毁的 3 种方法:

        ① 调用 main 函数的返回语句;

        ② 调用 pthread_join() 函数;

        ③ 调用 pthread_detach() 函数;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1007115.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微服务架构笔记

文章目录 简介微服务架构微服务方案对比注册中心 简介 SpringCloud&#xff08;多种框架组件技术集合的总框架&#xff09;笔记 传统单体架构VS微服务分布式架构 单体架构特点? 简单方便&#xff0c;高度耦合&#xff0c;扩展性差&#xff0c;适合小型项目。例如:学生管理系…

VMware Workstation虚拟机网络配置及配置自动启动

目录 一、网络配置二、配置自动启动1.VMware 中配置虚拟机自启动2.系统服务中配置 VMware 服务自启动 一、网络配置 本文将虚拟机 IP 与主机 IP 设置为同一个网段。 点击 “编辑” -> “虚拟网络编辑器(N)…”&#xff1a; 点击 “更改设置”&#xff1a; 将 VMnet0 设置…

Linux下安装和使用MySQL的详细教程

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

机器学习入门案例(2)之使用逻辑回归预测房子是否能被租出去

大家好&#xff0c;我是邵奈一&#xff0c;一个不务正业的程序猿、正儿八经的斜杠青年。 1、世人称我为&#xff1a;被代码耽误的诗人、没天赋的书法家、五音不全的歌手、专业跑龙套演员、不合格的运动员… 2、这几年&#xff0c;我整理了很多IT技术相关的教程给大家&#xff0…

gitlab操作

1. 配置ssh 点击访问 2. 创建新分支与切换新分支 git branch 新分支名 // 创建 git checkout 新分支名 // 切换到新分支3. 查看当前分支 git branch*所指的就是当前所在分支 4. 本地删除文件后与远程git同步 git add -A git commit -m "del" git push

编码转换流

同理&#xff0c;创建f1和f2方法&#xff0c;分别测试OutputStreamWriter和InputStreamReader 也是主要分三步&#xff0c;即1创建流 2使用流 3关流 OutputStreamWriter f1方法 因为要操作流&#xff0c;所以先创建一个try-catch-finally结构&#xff0c;创建流对象Out…

【2596. 检查骑士巡视方案】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 骑士在一张 n x n 的棋盘上巡视。在有效的巡视方案中&#xff0c;骑士会从棋盘的 左上角 出发&#xff0c;并且访问棋盘上的每个格子 恰好一次 。 给你一个 n x n 的整数矩阵 grid &#xff0c;由范…

无涯教程-JavaScript - ISERR函数

描述 如果ISERR函数引用的是Excel错误(&#xff03;N/A错误除外),则ISERR函数返回逻辑值TRUE。否则返回FALSE。 语法 ISERR (value)争论 Argument描述Required/OptionalvalueAn errorRequired Notes 此函数在公式中用于测试计算输出很有用。与IF函数结合使用时,此函数提供…

综合能力 ---- 2. 法律法规

1. 法律法规 1.1 电信条例 电信条例概述电信市场规定电信服务规定电信建设规定电信安全规定 1.2 网间互联管理规定 网间互联概述经营者的互联义务互联时限 1.3 网络安全法 网络安全法概述网络运行安全规定网络信息安全规定 2. 电信条例修订的目的 《电信条例》于2016年做…

fatal error: linux/compiler-gcc9.h: No such file or directory

linux 找到README文件 cd /mnt/e/CLionProjects/linux-3.10.99/linux-3.10.99 sudo useradd linux3x sudo passwd linux3x sudo mkdir /home/linux3x sudo chown linux3x:linu3x /home/linux3x sudo chmod 755 /home/linux3x su - linux3x mkdir ~/build mkdir ~/build/kerne…

精品基于NET实现的民族文化宣传网站

《[含文档PPT源码等]精品基于NET实现的民族文化宣传网站》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程等 软件开发环境及开发工具&#xff1a; 开发软件&#xff1a;VS 2017 &#xff08;版本2017以上即可&#xff0c;不能低于2017&#xff09; 数…

python 语法入门

文章目录 前言python 语法入门1. 语句分隔符2. 注释3. pep8规范4. 变量5. 扩展5.1. 运行此行代码的过程 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不会…

分享一下在微信小程序上怎么实现投票功能

微信小程序已经成为一种非常受欢迎的移动应用&#xff0c;可以通过它来实现各种功能&#xff0c;包括投票功能。下面&#xff0c;我们将为大家详细介绍如何在微信小程序上实现投票功能。 一、确定投票功能的目标 在策划投票功能之前&#xff0c;需要明确自己的目标。目标可以是…

【python】CliffWalking悬崖寻路问题

强化学习 简介gym库-CliffWalkingSARSAQ-learning 示例SARSAQ-learning 简介 机器学习&#xff1a;监督学习、非监督学习、强化学习 模仿人类和动物的试错机制进行学习智能体与环境交互&#xff0c;根据当前的环境状态s&#xff0c;按照一定策略采取行动a&#xff0c;获得回报r…

使用 CSS 伪类的attr() 展示 tooltip

效果图: 使用场景: 使用React渲染后台返回的数据, 遍历以列表的形式展示, 可能简要字段内容需要鼠标放上去才显示的 可以借助DOM的自定义属性和CSS伪类的attr来实现 所有代码: <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-…

Linux之文本搜索工具--grep

目录 Linux之文本搜索工具--grep 作用 格式 参数 注意 示例 操作对象文件&#xff1a;/etc/passwd grep过滤命令示例 Linux之文本搜索工具--grep 作用 grep是linux中一种强大的文件搜索过滤工具&#xff0c;可以按照正则表达式检索文件内容&#xff0c;并把匹配的结果显…

Ubuntu安装与配置MySQL简要记录

目标 前置条件&#xff1a;Virtualbox虚拟机下Ubuntu20.04 目标MySQL版本&#xff1a;8.0.34 目标效果&#xff1a;安装并配置MySQL&#xff0c;开启远程连接且使用windows下的DataGrip进行管理 安装 sudo apt install mysql-server 通过apt安装的mysql只需一行&#xff0c;…

LeetCode——动态规划篇(一)

刷题顺序及思路来源于代码随想录&#xff0c;网站地址&#xff1a;https://programmercarl.com 目录 509. 斐波那契数 - 力扣&#xff08;LeetCode&#xff09; 70. 爬楼梯 - 力扣&#xff08;LeetCode&#xff09; 746. 使用最小花费爬楼梯 - 力扣&#xff08;LeetCode&a…

【C++】泛型编程 | 函数模板 | 类模板

一、泛型编程 泛型编程是啥&#xff1f; 编写一种一般化的、可通用的算法出来&#xff0c;是代码复用的一种手段。 类似写一个模板出来&#xff0c;不同的情况&#xff0c;我们都可以往这个模板上去套。 举个例子&#xff1a; void Swap(int& a, int& b) {int tmp …

智能驾驶感知技术的综述与展望

目录 1 智能驾驶环境感知的目的 1.1 智能驾驶感知技术的定义和作用 1.2 基于传感器的智能驾驶感知技术 1.3 基于深度学习的智能驾驶感知技术 2 环境感知的手段与方法 2.1 感知技术在智能驾驶中的应用与发展 2.2 智能驾驶决策系统的设计与优化 2.3 控制技术在智能驾驶中的应…