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
    评论
### 回答1: 《Linux+, 第七: Linux 文件系统》是《Linux+认证教程》中的第七,重点介绍了Linux操作系统中的文件系统。在这一中,读者将了解到Linux文件系统的基本概念、常用的文件系统类型以及文件系统的管理和维护等内容。 首先,本开始介绍了Linux文件系统的基本概念,包括文件和目录的概念以及在Linux中的表示方式。读者将学习到如何使用文件路径和文件名来访问文件和目录。同时,还介绍了Linux系统中的特殊目录,如根目录、用户主目录和共享目录等。 接着,本继续讲解了常见的文件系统类型。Linux支持多种文件系统类型,如EXT4、XFS、Btrfs等。读者将了解到每种文件系统类型的特点和适用场景,并学习如何在Linux中创建和格式化不同类型的文件系统。 然后,本讲解了文件系统的管理和维护。读者将学习如何使用命令行工具来管理和操作文件系统,如创建、删除、复制和移动文件等。同时,还介绍了文件系统的权限和属性配置,如设置文件的拥有者和权限等。 最后,本还涉及了文件系统的备份和恢复。读者将学习如何使用备份工具来对文件系统进行备份,以及如何从备份中恢复数据。 通过学习本内容,读者将深入了解Linux文件系统的原理和操作方法。这对于Linux系统管理员和开发人员来说非常重要,因为文件系统是Linux操作系统中最基础和核心的部分之一。掌握了文件系统的知识,读者将能够更好地管理和维护Linux系统,并解决文件系统相关的问题。 ### 回答2: 《Linux头歌》是一本关于Linux操作系统的技术书籍,第七主要讲述了Linux文件系统的管理和操作。本主要涵盖了以下几个方面的内容。 首先,本介绍了Linux文件系统的基本概念和特点。Linux文件系统采用了类似于树状结构的层次目录结构,以根目录"/"为起点,通过不同的目录和文件来组织和管理数据。同时,Linux文件系统还具有对文件和目录进行权限管理的功能,确保安全性。 接着,本详细介绍了如何在Linux系统中创建、删除、复制和移动文件和目录。通过命令行工具或图形界面工具,用户可以轻松地对文件和目录进行操作,满足不同的需求。此外,还介绍了文件和目录的属性和权限设置,确保文件的安全性。 然后,本讲解了Linux文件系统中的硬链接和软链接的概念和用法。硬链接是指多个文件指向同一个物理存储空间,而软链接是指一个文件指向另一个文件,类似于快捷方式。用户可以根据需要使用不同的链接方式,帮助管理和组织文件。 最后,本还介绍了Linux文件系统的挂载和卸载操作。在Linux系统中,用户可以通过挂载操作将外部设备或远程文件系统与本地文件系统连接起来,以便访问和操作外部文件。同时,也可以通过卸载操作安全地断开与外部文件系统的连接。 总之,第七Linux头歌》详细介绍了Linux文件系统的管理和操作技巧,帮助读者更好地理解和掌握Linux操作系统的文件系统特性和使用方法。无论是初学者还是有一定经验的用户,都可以从中获得实用的知识和技能,提高对Linux系统的操作能力。 ### 回答3: 《Linux内核设计与实现》是一本经典的Linux内核相关书籍,其中第七主要介绍了Linux内核的关键组成部分——系统调用及库函数。系统调用是操作系统内核提供给用户程序的一组接口,它们允许用户程序通过内核来访问底层系统资源和服务。这一内容对于深入理解 Linux 内核的使用和开发具有重要意义。 首先,第七详细介绍了系统调用的实现原理和机制。作者解析了系统调用表的结构和功能,并且详细说明了Linux内核是如何通过系统调用号来定位和调用相应的系统调用函数的。这些系统调用函数在内核空间中运行,并能够处理用户程序发起的请求,实现具体的功能。 其次,本还介绍了用户空间和内核空间之间的切换机制。当用户程序发起系统调用的时候,会触发用户态和内核态之间的转换,在转换过程中,内核会根据系统调用号找到对应的系统调用函数,并执行相应的操作。这一详细分析了切换过程的细节以及相关的数据结构。 此外,本还对一些常用的系统调用进行了详细介绍,如文件操作相关的系统调用(如open、read、write等),进程管理相关的系统调用(如fork、execve、wait等),以及网络通信相关的系统调用(如socket、bind、connect等)。对于开发者来说,熟悉这些系统调用的使用方法和原理非常重要,能够帮助他们更好地设计和开发Linux内核的应用程序。 总之,第七Linux内核设计与实现》详细介绍了Linux内核的系统调用和库函数的实现原理和机制,以及常用系统调用的使用方法。通过学习这一的内容,读者能够深入理解Linux内核的工作原理,对于使用和开发Linux内核应用程序具有指导意义。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值