Linux 三十六章

​​​​​​​

🐶博主主页:@ᰔᩚ. 一怀明月ꦿ 

❤️‍🔥专栏系列:线性代数C初学者入门训练题解CC的使用文章「初学」C++linux

🔥座右铭:“不要等到什么都没有了,才下定决心去做”

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

目录

信号量

sem_init

sem_destroy 

sem_wait

sem_post

基于环形队列的CP问题

环形队列的生产者消费者模型

线程池 

localtime时间戳转化

mkdir系统调用

bind绑定成员函数

懒汉饿汉单例模式

懒汉模式:

饿汉模式:

懒汉和饿汉相同点:

线程池源码实现


信号量

1)信号量本质就是一把计数器

2)申请信号量本质就是预订资源

3)PV操作是原子的

PV操作是信号量的基本操作,用于对信号量的值进行增加(V操作)和减少(P操作)

快速认识信号量的接口

头文件:#include<semaphore.h>

sem_init

在Linux中,sem_init 函数用于初始化一个未命名的信号量。

其函数声明如下:
 

int sem_init(sem_t *sem, int pshared, unsigned int value);
* sem:指向要初始化的信号量的指针。
* pshared:指定信号量是在进程间共享(非0)还是在当前进程内共享(0)。
* value:指定信号量的初始值。

sem_destroy 

sem_destroy 函数用于销毁一个未命名的信号量。

其函数声明如下:

int sem_destroy(sem_t *sem);

sem_wait

在Linux中,sem_wait 函数用于执行一个P操作,即等待(wait)信号量的值减少。

其函数声明如下:

int sem_wait(sem_t *sem);
* sem:指向要操作的信号量的指针。
当调用 sem_wait 函数时,它会尝试减少信号量的值。如果信号量的值大于0,
则将其减少;如果信号量的值已经为0,则该操作将被阻塞,直到信号量的值不为0。
一旦成功执行了P操作,即信号量的值被减少,进程或线程可以继续执行接下来的代码段。

sem_post

在Linux中,sem_post 函数用于执行一个V操作,即增加(post)信号量的值。

其函数声明如下:

int sem_post(sem_t *sem);
* sem:指向要操作的信号量的指针。
当调用 sem_post 函数时,它会增加信号量的值。这通常用于释放资源或信号其他进程或线程可以继续执行。
如果有其他进程或线程正在等待该信号量(通过 sem_wait 阻塞),则调用 sem_post 后会使其中一个等
待的进程或线程继续执行。

基于环形队列的CP问题

1.生产者不能把消费者套圈

2.消费者不能超过生产者

生产者和消费者只有两种场景指向同一个位置

1)为空:只能让生产者跑(互斥)

2)未满:只能让消费者跑(互斥)

其他情况,生产者和消费者不会指向同一个位置(同步)

伪代码

资源分为空间和数据

需要两个信号量
Sem_space
Sem_data

生产者:
{
    P(sem_space)
    //生产行为
    V(sem_data)
}

生产者:
{
    P(sem_data)
    //生产行为
    V(sem_space)
}

多生产者和多消费者

为了保证临界资源的安全性,我们需要通过加锁实现生产者之间的互斥

现在就有一个问题?

我们线程是先申请资源还是,先申请信号量呢?

答案是,先申请信号量,因为我们可以让多个生产者先申请信号量,然后阻塞在加锁哪里,这样就可以节省申请信号量的时间

环形队列的生产者消费者模型

线程池 

localtime时间戳转化

在 Linux 中,localtime 函数是用于将时间戳(自 1970 年 1 月 1 日以来的秒数)转换为本地时间的函数。

它的函数原型通常在 time.h 头文件中声明

struct tm *localtime(const time_t *timep);
这个函数接受一个 time_t 类型的指针作为参数,返回一个指向 tm 结构体的指针,
该结构体包含了年、月、日、时、分、秒等本地时间信息。

mkdir系统调用

在Linux中,mkdir是一个系统调用,用于创建新的目录。系统调用是操作系统提供给应用程序的接口,允许应用程序直接请求操作系统执行某些特定的操作。

mkdir系统调用的原型如下:

#include <sys/stat.h>
#include <sys/types.h>

int mkdir(const char *pathname, mode_t mode);
pathname:要创建的目录的路径名。
mode:新目录的权限模式。可以使用chmod符号或八进制表示(例如0755),用于指定新目录的权限。
通常情况下,新目录默认权限为0777,但会受到umask设置的影响。

以下是一个简单的C语言示例,展示了如何使用mkdir系统调用来创建新的目录:

#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
int main() {
    const char* dir = "/path/to/new/dir";
    mode_t mode = 0777;
    int result = mkdir(dir, mode);
    if (result == 0) {
        printf("Directory created successfully.\n");
    } else {
        perror("Error creating directory");
    }
    return 0;
}
请注意,为了使用mkdir系统调用,你需要包含sys/types.h和sys/stat.h头文件,并链接libc库(
使用gcc时会自动链接)。

bind绑定成员函数

bind () 函数
std::bind()函数作为函数的适配器,它可以扩大函数是使用场合,使得函数更加灵活的被使用。
template<class F, class… Args>
bind(F&&f, Args&&… args);
参数:
f 可以是function object,函数指针,函数引用,成员函数指针,或者数据成员的指针,lambda表达式。
返回值:function object

事例
#include <iostream>
#include <functional>

using namespace std;
using namespace std::placeholders;

class test_callback
{
public:
    test_callback(void):a(10),b(100){ }
    typedef function<void(int,int)> callback;
    void use_value(callback func) {
        cout << "value a is " << a << endl;
        cout << "value b is " << b << endl;
        func(a, b);
    }
private:
    int a;
    int b;
};

class client
{
public:
    client(){ this->value = 2; }
    static void print_sum(int a, int b, int c) {
        cout << a + b +c << endl;
    }
    void print_multiply(int a, int b, int c, int d) {
        cout << a * b * c * d << endl;
        cout << "client value is " << this->value << endl; 
    }
private:
    int value;
};

int main(int argc, char *argv[])
{
    test_callback test1;
    client client1;
    test1.use_value(bind(client::print_sum, _2, _1, 0));
    test1.use_value(bind(&client::print_multiply, &client1, _1, _2, 2, 3));
    return 0;
}
重点是在使用non static function时要加&获取nonstatic 成员函数地址
结果:
value a is 10
value b is 100
110
value a is 10
value b is 100
6000
client value is 2

懒汉饿汉单例模式

C++中的单例模式、懒汉模式和饿汉模式。单例模式在面试和实际开发中都非常重要,其构造函数和instance成员变量分别采用private和static修饰,通过get_instance函数获取单例对象。懒汉模式存在线程安全问题,可通过添加锁解决。饿汉模式则是懒汉模式的一种优化,通过提前加载instance避免线程安全问题。


饿汉模式:程序运行即创建对象并实例化,静态实现所以线程是安全的

懒汉模式:创建对象不实例化,需要的时候才实例化,线程不安全需要(加锁)

懒汉模式:

1)构造函数设为私有
2)instance//单例为静态成员变量,类内声明,类外初始化static 类名* instance
类名* 类名::instance=nullptr;//类外定义
3)创建对外接口,通过这个获取单例

 Static 类名* getinstance()
{
    //这里为什么要用俩个if呢?因为我们在内层if进行加锁了,加锁为了保证只有一个线程去创建单例。其实可以把锁加在外层if,但是这样会导致每个线程都会去申请锁,这样导致资源浪费,所以我们把锁加在内层的if,只要有一个线程创建了单例,那其他线程就不会进入到内层if
    if(instance==nullptr)
    {
         //这里可以加一把锁
         if(instance==nullptr)
        {
            instance=new 类名();
        }
        //解锁
    }
    return instance;
}

饿汉模式:

1)构造函数设为私有
2)instance//单例为静态成员变量,类内声明,类外初始化static 类名* instance
类名* 类名::instance=new 类名();//类外定义
3)创建对外接口,通过这个获取单例

Static 类名* getinstance()
{
    return instance;
}
懒汉和饿汉相同点:


1)都需要将构造函数设置为私有的
2)都需要静态的类类型指针变量
懒汉和饿汉不同点:
懒汉你要使用的时候才创建单例(多线程中,是线程不安全的,可以通过加锁实现安全)
饿汉是使用之前就创建单例(多线程中,是线程安全的)

使用懒汉单例模式的原因
懒汉单例模式的主要作用是在第一次使用类时才创建类的实例,从而节省资源。在某些情况下,类的实例在程序运行期间只需要创建一次,如果提前创建,可能会浪费资源。懒汉单例模式就是在这种情况下使用的。

例如,线程池类在程序运行期间只需要创建一次,如果提前创建,可能会导致线程在等待任务时提前创建线程,从而浪费资源。使用懒汉单例模式,可以在第一次使用线程池时才创建线程池实例,从而避免这种情况。总结来说,懒汉单例模式的主要作用是在第一次使用类时才创建类的实例,从而节省资源。

线程池源码实现

 🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸

  • 20
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux网络编程(总共41集) 讲解Linux网络编程知识,分以下四个篇Linux网络编程之TCP/IP基础篇 Linux网络编程之socket编程篇 Linux网络编程之进程间通信篇 Linux网络编程之线程篇 Linux网络编程之TCP/IP基础篇 01TCPIP基础(一) ISO/OSI参考模型 TCP/IP四层模型 基本概念(对等通信、封装、分用、端口) 02TCPIP基础(二) 最大传输单元(MTU)/路径MTU 以太网帧格式 ICMP ARP RARP 03TCPIP基础(三) IP数据报格式 网际校验和 路由 04TCPIP基础(四) TCP特点 TCP报文格式 连接建立三次握手 连接终止四次握手 TCP如何保证可靠性 05TCPIP基础(五) 滑动窗口协议 UDP特点 UDP报文格式 Linux网络编程之socket编程篇 06socket编程(一) 什么是socket IPv4套接口地址结构 网络字节序 字节序转换函数 地址转换函数 套接字类型 07socket编程(二) TCP客户/服务器模型 回射客户 /服务器 socket、bind、listen、accept、connect 08socket编程(三) SO_REUSEADDR 处理多客户连接(process-per-conection) 点对点聊天程序实现 09socket编程(四) 流协议与粘包 粘包产生的原因 粘包处理方案 readn writen 回射客户/服务器 10socket编程(五) read、write与recv、send readline实现 用readline实现回射客户/服务器 getsockname、getpeername gethostname、gethostbyname、gethostbyaddr 11socket编程(六) TCP回射客户/服务器 TCP是个流协议 僵进程与SIGCHLD信号 12socket编程(七) TCP 11种状态 连接建立三次握手、连接终止四次握手 TIME_WAIT与SO_REUSEADDR SIGPIPE 13socket编程(八) 五种I/O模型 select 用select改进回射客户端程序 14socket编程(九) select 读、写、异常事件发生条件 用select改进回射服务器程序。 15socket编程(十) 用select改进第八点对点聊天程序 16socket编程(十一) 套接字I/O超时设置方法 用select实现超时 read_timeout函数封装 write_timeout函数封装 accept_timeout函数封装 connect_timeout函数封装 17socket编程(十二) select限制 poll 18socket编程(十三) epoll使用 epoll与select、poll区别 epoll LT/ET模式 19socket编程(十四) UDP特点 UDP客户/服务基本模型 UDP回射客户/服务器 UDP注意点 20socket编程(十五) udp聊天室实现 21socket编程(十六) UNIX域协议特点 UNIX域地址结构 UNIX域字节流回射客户/服务 UNIX域套接字编程注意点 22socket编程(十七) socketpair sendmsg/recvmsg UNIX域套接字传递描述符字 Linux网络编程之进程间通信篇 23进程间通信介绍(一) 进程同步与进程互斥 进程间通信目的 进程间通信发展 进程间通信分类 进程间共享信息的三种方式 IPC对象的持续性 24进程间通信介绍(二) 死锁 信号量 PV原语 用PV原语解决司机与售票员问题 用PV原语解决民航售票问题 用PV原语解决汽车租赁问题 25System V消息队列(一) 消息队列 IPC对象数据结构 消息队列结构 消息队列在内核中的表示 消息队列函数 26System V消息队列(二) msgsnd函数 msgrcv函数 27System V消息队列(三) 消息队列实现回射客户/服务器 28共享内存介绍 共享内存 共享内存示意图 管道、消息队列与共享内存传递数据对比 mmap函数 munmap函数 msync函数 29System V共享内存 共享内存数据结构 共享内存函数 共享内存示例 30System V信号量(一) 信号量 信号量集结构 信号量集函数 信号量示例 31System V信号量(二) 用信号量实现进程互斥示例 32System V信号量(三) 用信号集解决哲学家就餐问题 33System V共享内存与信号量综合 用信号量解决生产者消费者问题 实现shmfifo 34POSIX消息队列 POSIX消息队列相关函数 POSIX消息队列示例 35POSIX共享内存 POSIX共享内存相关函数 POSIX共享内存示例 Linux网络编程之线程篇 36线程介绍 什么是线程 进程与线程 线程优缺点 线程模型 N:1用户线程模型 1:1核心线程模型 N:M混合线程模型 37POSIX线程(一) POSIX线程库相关函数 用线程实现回射客户/服务器 38POSIX线程(二) 线程属性 线程特定数据 39POSIX信号量与互斥锁 POSIX信号量相关函数 POSIX互斥锁相关函数 生产者消费者问题 自旋锁与读写锁介绍 40POSIX条件变量 条件变量 条件变量函数 条件变量使用规范 使用条件变量解决生产者消费者问题 41一个简单的线程池实现 线程池性能分析 线程池实现 网络编程, Linux
《深入理解Linux内核》是一本经典的Linux内核书籍,由Daniel P. Bovet和Marco Cesati合著。该书深入剖析了Linux内核的各个方面,包括进程管理、内存管理、文件系统、网络协议栈等等,是学习Linux内核的重要参考资料。该书的目录包括: 第1部分 内核基础 第1 操作系统概述 第2 Linux内核概述 第3 进程管理 第4 进程间通信 第5 系统调用 第6 中断和异常 第7 内核数据结构 第8 内存管理 第2部分 进程管理 第9 进程描述符 第10 调度 第11 进程地址空间 第12 进程创建 第13 进程结束 第3部分 进程间通信 第14 信号 第15 管道 第16 FIFO和消息队列 第17 信号量 第18 共享内存 第19 内存映射 第4部分 系统调用 第20 系统调用实现 第21 标准C库 第5部分 中断和异常 第22 中断处理 第23 硬件设备 第24 字符驱动程序 第25 块驱动程序 第26 网络设备驱动程序 第6部分 内存管理 第27 物理内存管理 第28 虚拟内存管理 第29 内存映射 第7部分 文件系统 第30 文件系统概述 第31 Linux虚拟文件系统(VFS) 第32 文件系统实现 第33 文件系统mount和unmount 第8部分 网络 第34 网络概述 第35 套接字接口 第36 TCP/IP协议栈 第37 名字和地址解析 第38 套接字实现 第39 TCP/IP实现 第40 网络设备驱动程序 该书内容详实,通俗易懂,适合有一定编程经验的读者学习。如果您想深入了解Linux内核,这本书是必不可少的参考资料。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值