鸿蒙轻内核A核源码分析系列七 进程管理 (3)

news2025/1/14 17:59:31

本文记录下进程相关的初始化函数,如OsSystemProcessCreate、OsProcessInit、OsProcessCreateInit、OsUserInitProcess、OsDeInitPCB、OsUserInitProcessStart等。

1、LiteOS-A内核进程创建初始化通用函数

先看看一些内部函数,不管是初始化用户态进程还是内核态进程,都会使用这些函数,包含进程控制块初始化函数OsInitPCB、进程控制块初始化恢复函数OsDeInitPCB

1.1 进程控制块初始化函数OsInitPCB

进程控制块初始化函数OsInitPCB需要3个参数,第一个参数processCB是进程块指针,第二个参数为进程模式mode,分为内核态进程OS_KERNEL_MODE和用户态进程OS_USER_MODE。第三个参数用于设置进程名称。返回值为初始化成功LOS_OK还是失败LOS_ENOMEM。看下代码,⑴处设置进程控制块的信息,用户态进程还是内核态进程,进程状态设置为初始化状态,线程组编号设置为无效值,设置为默认掩码,定时器编号设置为无效值。⑵处初始化进程的双向链表。如果系统配置支持虚拟内存,则执行⑶判断初始化的进程是否为用户态进程,如果是用户态进程,则创建虚拟地址空间,如果创建失败,则把进程状态设置为未使用状态,然后返回错误码。⑷处表示如果是内核态进程,则指定进程的内核进程虚拟地址空间。有关虚拟地址空间的信息,请参考之前的系列文章。

如果执行CPUP特性,则执行⑸处代码,则为CPUP结构体申请内存空间。⑹处,如果开启了LOSCFG_SECURITY_VID,则V初始化ID映射链表。⑺处,如果开启了安全能力LOSCFG_SECURITY_CAPABILITY,则进行相应的初始化。⑻处为进程设置一个名称。

    STATIC UINT32 OsInitPCB(LosProcessCB *processCB, UINT32 mode, const CHAR *name)
    {
⑴      processCB->processMode = mode;
        processCB->processStatus = OS_PROCESS_STATUS_INIT;
        processCB->parentProcessID = OS_INVALID_VALUE;
        processCB->threadGroupID = OS_INVALID_VALUE;
        processCB->umask = OS_PROCESS_DEFAULT_UMASK;
        processCB->timerID = (timer_t)(UINTPTR)MAX_INVALID_TIMER_VID;

⑵      LOS_ListInit(&processCB->threadSiblingList);
        LOS_ListInit(&processCB->childrenList);
        LOS_ListInit(&processCB->exitChildList);
        LOS_ListInit(&(processCB->waitList));

    #ifdef LOSCFG_KERNEL_VM
⑶      if (OsProcessIsUserMode(processCB)) {
            processCB->vmSpace = OsCreateUserVmSpace();
            if (processCB->vmSpace == NULL) {
                processCB->processStatus = OS_PROCESS_FLAG_UNUSED;
                return LOS_ENOMEM;
            }
        } else {
⑷          processCB->vmSpace = LOS_GetKVmSpace();
        }
    #endif

    #ifdef LOSCFG_KERNEL_CPUP
⑸      processCB->processCpup = (OsCpupBase *)LOS_MemAlloc(m_aucSysMem1, sizeof(OsCpupBase));
        if (processCB->processCpup == NULL) {
            return LOS_ENOMEM;
        }
        (VOID)memset_s(processCB->processCpup, sizeof(OsCpupBase), 0, sizeof(OsCpupBase));
    #endif

    #ifdef LOSCFG_SECURITY_VID
⑹      status_t status = VidMapListInit(processCB);
        if (status != LOS_OK) {
            return LOS_ENOMEM;
        }
    #endif

⑺  #ifdef LOSCFG_SECURITY_CAPABILITY
        OsInitCapability(processCB);
    #endif

⑻      if (OsSetProcessName(processCB, name) != LOS_OK) {
            return LOS_ENOMEM;
        }

        return LOS_OK;
    }

1.2 进程控制块初始化恢复函数OsDeInitPCB

在创建进程时,会执行该函数,恢复进程控制块信息到初始化之前的状态。⑴处释放进程的资源,包含地址空间、文件、安全能力、定时器等占用的内存。如果存在父进程,则执行⑵从父进程的兄弟列表上删除。如果进程属于进程组,则从进程组中退出。然后执行⑷设置进程状态为退出态,把进程放入待回收链表中。

    STATIC VOID OsDeInitPCB(LosProcessCB *processCB)
    {
        UINT32 intSave;
        ProcessGroup *group = NULL;

        if (processCB == NULL) {
            return;
        }

⑴      OsProcessResourcesToFree(processCB);

        SCHEDULER_LOCK(intSave);
        if (processCB->parentProcessID != OS_INVALID_VALUE) {
⑵          LOS_ListDelete(&processCB->siblingList);
            processCB->parentProcessID = OS_INVALID_VALUE;
        }

⑶      if (processCB->group != NULL) {
            OsExitProcessGroup(processCB, &group);
        }

⑷      processCB->processStatus &= ~OS_PROCESS_STATUS_INIT;
        processCB->processStatus |= OS_PROCESS_FLAG_EXIT;
        LOS_ListHeadInsert(&g_processRecycleList, &processCB->pendList);
        SCHEDULER_UNLOCK(intSave);

        (VOID)LOS_MemFree(m_aucSysMem1, group);
        OsWriteResourceEvent(OS_RESOURCE_EVENT_FREE);
        return;
    }

2、 LiteOS-A内核系统进程创建函数OsSystemProcessCreate

系统进程创建函数OsSystemProcessCreate在文件kernel\common\los_config.c中被调用,在系统启动阶段创建系统进程。该函数又调用OsProcessInit,我们首先看下函数OsProcessInit。

2.1 进程初始化函数OsProcessInit

进程初始化函数OsProcessInit为进程控制块申请内存,初始化进程相关的进程链表。我们看下代码,⑴处获取配置的进程最大数值,然后计算需要的内存大小。⑵处申请内存,初始化申请的内存块。⑶处初始化空闲进程双向链表和待回收进程双向链表。
⑷处初始化每一个进程,社区进程编号、进程状态,然后把每一个进程放到空闲进程链表里。⑸处设置Idle进程编号为0,用户根进程编号为1,系统根进程编号为2,然后执行LOS_ListDelete把这3个进程从阻塞链表上删除。

    STATIC UINT32 OsProcessInit(VOID)
    {
        UINT32 index;
        UINT32 size;

⑴      g_processMaxNum = LOSCFG_BASE_CORE_PROCESS_LIMIT;
        size = g_processMaxNum * sizeof(LosProcessCB);

⑵      g_processCBArray = (LosProcessCB *)LOS_MemAlloc(m_aucSysMem1, size);
        if (g_processCBArray == NULL) {
            return LOS_NOK;
        }
        (VOID)memset_s(g_processCBArray, size, 0, size);

⑶      LOS_ListInit(&g_freeProcess);
        LOS_ListInit(&g_processRecycleList);

⑷      for (index = 0; index < g_processMaxNum; index++) {
            g_processCBArray[index].processID = index;
            g_processCBArray[index].processStatus = OS_PROCESS_FLAG_UNUSED;
            LOS_ListTailInsert(&g_freeProcess, &g_processCBArray[index].pendList);
        }

⑸      g_kernelIdleProcess = 0; /* 0: The idle process ID of the kernel-mode process is fixed at 0 */
        LOS_ListDelete(&OS_PCB_FROM_PID(g_kernelIdleProcess)->pendList);

        g_userInitProcess = 1; /* 1: The root process ID of the user-mode process is fixed at 1 */
        LOS_ListDelete(&OS_PCB_FROM_PID(g_userInitProcess)->pendList);

        g_kernelInitProcess = 2; /* 2: The root process ID of the kernel-mode process is fixed at 2 */
        LOS_ListDelete(&OS_PCB_FROM_PID(g_kernelInitProcess)->pendList);

        return LOS_OK;
    }

2.2 进程创建初始化函数OsProcessCreateInit

该函数用于创建进程时的一些初始化操作,主要是文件系统、安全能力、进程组等等。需要3个参数,分别是进程控制块指针,标记用户态还是内核态进程的flags,进程名称name。首先执行⑴调用OsInitPCB()对进程控制块进行初始化,然后,如果配置支持了虚拟文件系统VFS,则执行⑵为进程分别文件。⑶处根据进程号创建进程组。如果支持安全能力,则执行⑷创建用户。如果初始化失败,会执行⑸恢复进程控制块到初始化之前的状态。

    STATIC UINT32 OsProcessCreateInit(LosProcessCB *processCB, UINT32 flags, const CHAR *name)
    {
        ProcessGroup *group = NULL;
⑴      UINT32 ret = OsInitPCB(processCB, flags, name);
        if (ret != LOS_OK) {
            goto EXIT;
        }

    #ifdef LOSCFG_FS_VFS
⑵      processCB->files = alloc_files();
        if (processCB->files == NULL) {
            ret = LOS_ENOMEM;
            goto EXIT;
        }
    #endif

⑶      group = OsCreateProcessGroup(processCB->processID);
        if (group == NULL) {
            ret = LOS_ENOMEM;
            goto EXIT;
        }

    #ifdef LOSCFG_SECURITY_CAPABILITY
⑷      processCB->user = OsCreateUser(0, 0, 1);
        if (processCB->user == NULL) {
            ret = LOS_ENOMEM;
            goto EXIT;
        }
    #endif

        return LOS_OK;

    EXIT:
⑸      OsDeInitPCB(processCB);
        return ret;
    }

2.3 系统进程创建函数OsSystemProcessCreate

接下来,我们看看系统进程创建函数OsSystemProcessCreate的源代码。⑴处开始先后调用OsProcessInit、OsProcessCreateInit初始化内核态根进程,⑵处进程的状态不再是初始化状态。⑶处从内核进程获取全局进程组指针g_processGroup,然后初始化进程组的双向链表。这样看来,所有的进程组都会挂载到内核进程的进程组节点上。⑷处初始化内核空闲进程,内核空闲进程的父进程也是内核态根进程,插入到进程组链表,设置空闲进程的状态不再是初始化状态。执行⑸创建空闲任务,然后设置空闲进程的线程组编号为空闲线程编号。

    LITE_OS_SEC_TEXT_INIT UINT32 OsSystemProcessCreate(VOID)
    {
⑴      UINT32 ret = OsProcessInit();
        if (ret != LOS_OK) {
            return ret;
        }

        LosProcessCB *kerInitProcess = OS_PCB_FROM_PID(g_kernelInitProcess);
        ret = OsProcessCreateInit(kerInitProcess, OS_KERNEL_MODE, "KProcess");
        if (ret != LOS_OK) {
            return ret;
        }

⑵      kerInitProcess->processStatus &= ~OS_PROCESS_STATUS_INIT;
⑶      g_processGroup = kerInitProcess->group;
        LOS_ListInit(&g_processGroup->groupList);

⑷      LosProcessCB *idleProcess = OS_PCB_FROM_PID(g_kernelIdleProcess);
        ret = OsInitPCB(idleProcess, OS_KERNEL_MODE, "KIdle");
        if (ret != LOS_OK) {
            return ret;
        }
        idleProcess->parentProcessID = kerInitProcess->processID;
        LOS_ListTailInsert(&kerInitProcess->childrenList, &idleProcess->siblingList);
        idleProcess->group = kerInitProcess->group;
        LOS_ListTailInsert(&kerInitProcess->group->processList, &idleProcess->subordinateGroupList);
    #ifdef LOSCFG_SECURITY_CAPABILITY
        idleProcess->user = kerInitProcess->user;
    #endif
    #ifdef LOSCFG_FS_VFS
        idleProcess->files = kerInitProcess->files;
    #endif
        idleProcess->processStatus &= ~OS_PROCESS_STATUS_INIT;

⑸      ret = OsIdleTaskCreate();
        if (ret != LOS_OK) {
            return ret;
        }
        idleProcess->threadGroupID = OsGetIdleTaskId();

        return LOS_OK;
    }

3. LiteOS-A内核用户进程创建函数OsUserInitProcess

系统启动阶段,OsUserInitProcess启动init进程。该函数在device开发板目录下系统初始化文件中调用,如system_init.c等等。该函数需要开启LOSCFG_KERNEL_DYNLOAD宏,否则函数体内容为空。在阅读函数OsUserInitProcess的源码前,先看看该函数调用的其他函数,如OsLoadUserInit、OsUserInitStackAlloc、OsUserInitProcessStart等等。

3.1 加载用户初始化数据函数OsLoadUserInit

该函数用于加载用户数据。⑴处从链接脚本获取text、bss的开启和结束地址,然后计算bss段、初始化段的大小。⑵处进行一些必要的校验,是否针对内存页对齐,内存段长度是否合理等。然后执行⑶,申请物理内存页,然后把用户初始化数据复制到申请的内存页。⑷处进行虚实映射。如果bss段长度不为0,执行⑸把bss段的内存区域清零。

STATIC UINT32 OsLoadUserInit(LosProcessCB *processCB)
{
    /*              userInitTextStart               -----
     * | user text |
     *
     * | user data |                                initSize
     *              userInitBssStart  ---
     * | user bss  |                  initBssSize
     *              userInitEnd       ---           -----
     */
    errno_t errRet;
    INT32 ret;
⑴  CHAR *userInitTextStart = (CHAR *)&__user_init_entry;
    CHAR *userInitBssStart = (CHAR *)&__user_init_bss;
    CHAR *userInitEnd = (CHAR *)&__user_init_end;
    UINT32 initBssSize = userInitEnd - userInitBssStart;
    UINT32 initSize = userInitEnd - userInitTextStart;
    VOID *userBss = NULL;
    VOID *userText = NULL;

⑵  if ((LOS_Align((UINTPTR)userInitTextStart, PAGE_SIZE) != (UINTPTR)userInitTextStart) ||
        (LOS_Align((UINTPTR)userInitEnd, PAGE_SIZE) != (UINTPTR)userInitEnd)) {
        return LOS_EINVAL;
    }

    if ((initSize == 0) || (initSize <= initBssSize)) {
        return LOS_EINVAL;
    }

⑶  userText = LOS_PhysPagesAllocContiguous(initSize >> PAGE_SHIFT);
    if (userText == NULL) {
        return LOS_NOK;
    }

    errRet = memcpy_s(userText, initSize, (VOID *)&__user_init_load_addr, initSize - initBssSize);
    if (errRet != EOK) {
        PRINT_ERR("Load user init text, data and bss failed! err : %d\n", errRet);
        goto ERROR;
    }
⑷  ret = LOS_VaddrToPaddrMmap(processCB->vmSpace, (VADDR_T)(UINTPTR)userInitTextStart, LOS_PaddrQuery(userText),
                               initSize, VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE |
                               VM_MAP_REGION_FLAG_FIXED | VM_MAP_REGION_FLAG_PERM_EXECUTE |
                               VM_MAP_REGION_FLAG_PERM_USER);
    if (ret < 0) {
        PRINT_ERR("Mmap user init text, data and bss failed! err : %d\n", ret);
        goto ERROR;
    }

    /* The User init boot segment may not actually exist */
⑸  if (initBssSize != 0) {
        userBss = (VOID *)((UINTPTR)userText + userInitBssStart - userInitTextStart);
        errRet = memset_s(userBss, initBssSize, 0, initBssSize);
        if (errRet != EOK) {
            PRINT_ERR("memset user init bss failed! err : %d\n", errRet);
            goto ERROR;
        }
    }

    return LOS_OK;

ERROR:
    (VOID)LOS_PhysPagesFreeContiguous(userText, initSize >> PAGE_SHIFT);
    return LOS_NOK;
}

3.2 用户初始化栈函数OsUserInitStackAlloc

该函数需要2个参数,第一个参数为进程控制块,第二个参数为输出参数,用于获取用户任务栈的大小。⑴处用户任务栈大小对页进行对齐,然后申请内存区域,然后执行⑵设置内存区域类型,并社区内存区域标签为栈。然后设置输出参数为任务栈大小,并返回用户栈空间的开始地址。

STATIC VOID *OsUserInitStackAlloc(LosProcessCB *processCB, UINT32 *size)
{
    LosVmMapRegion *region = NULL;
⑴  UINT32 stackSize = ALIGN(OS_USER_TASK_STACK_SIZE, PAGE_SIZE);

    region = LOS_RegionAlloc(processCB->vmSpace, 0, stackSize,
                             VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ |
                             VM_MAP_REGION_FLAG_PERM_WRITE, 0);
    if (region == NULL) {
        return NULL;
    }

⑵  LOS_SetRegionTypeAnon(region);
    region->regionFlags |= VM_MAP_REGION_FLAG_STACK;

    *size = stackSize;

    return (VOID *)(UINTPTR)region->range.base;
}

3.3 用户进程初始化开启函数OsUserInitProcessStart

用户进程初始化开启函数OsUserInitProcessStart用于创建线程,设置调度策略等。⑴处为用户态进程创建个线程,然后为进程设置优先级。⑵处设置进程状态为非初始化状态,然后执行⑶为任务设置调度策略和优先级。

STATIC UINT32 OsUserInitProcessStart(LosProcessCB *processCB, TSK_INIT_PARAM_S *param)
{
    UINT32 intSave;
    INT32 ret;

⑴  UINT32 taskID = OsCreateUserTask(processCB->processID, param);
    if (taskID == OS_INVALID_VALUE) {
        return LOS_NOK;
    }

    ret = LOS_SetProcessPriority(processCB->processID, OS_PROCESS_USERINIT_PRIORITY);
    if (ret != LOS_OK) {
        PRINT_ERR("User init process set priority failed! ERROR:%d \n", ret);
        goto EXIT;
    }

    SCHEDULER_LOCK(intSave);
⑵  processCB->processStatus &= ~OS_PROCESS_STATUS_INIT;
    SCHEDULER_UNLOCK(intSave);

⑶  ret = LOS_SetTaskScheduler(taskID, LOS_SCHED_RR, OS_TASK_PRIORITY_LOWEST);
    if (ret != LOS_OK) {
        PRINT_ERR("User init process set scheduler failed! ERROR:%d \n", ret);
        goto EXIT;
    }

    return LOS_OK;

EXIT:
    (VOID)LOS_TaskDelete(taskID);
    return ret;
}

3.4 用户态进程初始化函数OsUserInitProcess

用户态进程初始化函数OsUserInitProcess完成用户态进程的初始化。⑴处获取用户态根进程,然后调用函数创建用户态根进程,并调用函数OsLoadUserInit加载用户初始化数据。⑵处初始化用户栈,然后设置线程的初始化参数,⑶处完成用户态进程的创建。

LITE_OS_SEC_TEXT_INIT UINT32 OsUserInitProcess(VOID)
{
    UINT32 ret;
    UINT32 size;
    TSK_INIT_PARAM_S param = { 0 };
    VOID *stack = NULL;

⑴  LosProcessCB *processCB = OS_PCB_FROM_PID(g_userInitProcess);
    ret = OsProcessCreateInit(processCB, OS_USER_MODE, "Init");
    if (ret != LOS_OK) {
        return ret;
    }

    ret = OsLoadUserInit(processCB);
    if (ret != LOS_OK) {
        goto ERROR;
    }

⑵  stack = OsUserInitStackAlloc(processCB, &size);
    if (stack == NULL) {
        PRINT_ERR("Alloc user init process user stack failed!\n");
        goto ERROR;
    }

    param.pfnTaskEntry = (TSK_ENTRY_FUNC)(CHAR *)&__user_init_entry;
    param.userParam.userSP = (UINTPTR)stack + size;
    param.userParam.userMapBase = (UINTPTR)stack;
    param.userParam.userMapSize = size;
    param.uwResved = OS_TASK_FLAG_PTHREAD_JOIN;
⑶  ret = OsUserInitProcessStart(processCB, &param);
    if (ret != LOS_OK) {
        (VOID)OsUnMMap(processCB->vmSpace, param.userParam.userMapBase, param.userParam.userMapSize);
        goto ERROR;
    }

    return LOS_OK;

ERROR:
    OsDeInitPCB(processCB);
    return ret;
}

小结

本文介绍了进程管理的内核进程、用户态进程的初始化相关函数。

如果大家想更加深入的学习 OpenHarmony 开发的内容,不妨可以参考以下相关学习文档进行学习,助你快速提升自己:

OpenHarmony 开发环境搭建:https://qr18.cn/CgxrRy

《OpenHarmony源码解析》:https://qr18.cn/CgxrRy

  • 搭建开发环境
  • Windows 开发环境的搭建
  • Ubuntu 开发环境搭建
  • Linux 与 Windows 之间的文件共享
  • ……

系统架构分析:https://qr18.cn/CgxrRy

  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通信子系统
  • 驱动子系统
  • ……

OpenHarmony 设备开发学习手册:https://qr18.cn/CgxrRy

在这里插入图片描述

OpenHarmony面试题(内含参考答案):https://qr18.cn/CgxrRy

写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:https://qr21.cn/FV7h05

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

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

相关文章

助力618!你想便宜寄快递退换货吗?

家人们&#xff0c;姐妹们&#xff0c;马上就要到618了&#xff0c;每年一到这种重要的节日&#xff0c;我们都会买买买&#xff0c;但是我们有时候买了会发现这个商品不太满意&#xff0c;我们会选择退换货&#xff0c;或者给商家邮寄回去&#xff0c;但是这个运费可真的太贵了…

CRC计算单元

CRC计算单元 CRC是Cyclic Redundancy Check,循环冗余校验的缩写. 是一种检测数据错误的技术,主要用在数据通信和数据存储的方面. 但是这种技术只能检测到传输或存储的数据是否有误,没有将错误纠正的功能. 而CRC计算单元是一个独立的具备CRC计算功能的外设. AT32 MCU片上CRC计…

Web应用安全测试-认证功能缺陷

Web应用安全测试-认证功能缺陷 存在空口令 漏洞描述&#xff1a;认证登录环节允许空口令 测试方法&#xff1a; 找到网站登录页面&#xff0c;尝试输入用用户名&#xff0c;密码为空进行登录。 风险分析&#xff1a;攻击者可利用该漏洞登录网站后台&#xff0c;操作敏感数…

Warning: `ReactDOMTestUtils.act` is deprecated in favor of `React.act`.

问题&#xff1a;在代码中使用jest进行单元测试时&#xff0c;报错如下&#xff1a; 解决思路&#xff1a; 根据报错提示出来的 react-dom/test-utils 进行全局搜索&#xff0c;发现没有该引用&#xff0c;故进入该代码块中分析。发现代码中引入testing-library/react &#…

C++ 28 之 类对象作为类成员

#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> using namespace std;class Phone { public:string s_p_name;Phone(string p_name) {s_p_name p_name;cout << "phone的构造函数调用" << endl;}~Phone(){cout &…

BitMEX 联合创始人 Arthur Hayes 加入 Covalent 担任战略顾问

Arthur Hayes 加入 Covalent Network&#xff08;CQT&#xff09;&#xff0c;成为其战略顾问。 Hayes 认为 Covalent 与其竞争对手如 The Graph 相比&#xff0c;Covalent Network 的 CQT 代币一直被相对低估&#xff0c;他希望帮助 Covalent Network&#xff08;CQT&#x…

【Three.js】知识梳理二十一:Three.js性能优化和实践建议

Three.js 是一个功能强大的 3D 引擎&#xff0c;用于创建 WebGL 应用。尽管它功能强大&#xff0c;但在复杂的 3D 场景中保持高性能是一个挑战。本文将分享一些在使用 Three.js 时的性能优化提示&#xff0c;帮助你提高应用的运行效率。 1. 使用 stats.js 监视性能 在进行任何…

苦日子开始了,普通人应该怎么做?

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 以为疫情后&#xff0c;我们的收入会好起来&#xff0c;谁曾想连工作都快保不住了&#xff0c;这几年大家日子过的比较苦&#xff0c;很多人想多一份收入。 面对这种情况&#xff0c;我们普通人应该怎么办?如何多…

【秋招突围】2024届秋招笔试-阿里系列笔试题-第一套-三语言题解(Java/Cpp/Python)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系计划跟新各公司春秋招的笔试题 &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f497; &#x1f4e7; 清隆这边…

C++ 27 之 初始化列表

c27初始化列表.cpp #include <iostream> #include <string.h> using namespace std;class Students06{ public:int s_a;int s_b;int s_c;Students06(int a, int b, int c){s_a a;s_b b;s_c c;}// 初始化列表写法1&#xff1a;// Students06():s_a(4),s_b(5),s_…

使用QT绘制简单的动态数据折线图

两个核心类时QChart和QLineSeries 下面这个示例代码中&#xff0c;定时器每隔一段时间将曲线图中的数据点向右移动 一个单位&#xff0c;同时调整横坐标轴的范围&#xff0c;实现了一次滚动对应移动一个数据点的效果。 QLineSeries最多容纳40961024个点 #include <QtWidg…

【RabbitMQ】初识 RabbitMQ

初识 RabbitMQ 1.认识 RabbitMQ1.1 介绍1. 2.使用场景1.2.1 推送通知1.2.2 异步任务1.2.3 多平台应用的通信1.2.4 消息延迟1.2.5 远程过程调用 1.3 特性 2.基本概念2.1 生产者、消费者和代理2.2 消息队列2.3 交换机2.3.1 direct2.3.2 topic2.3.3 headers2.3.4 fanout 2.4 绑定2…

Downie for Mac v4.7.17 在线视频下载软件 安装(简单易学,小白轻松搞定)

Mac分享吧 文章目录 效果一、准备工作二、开始安装1、双击运行软件&#xff0c;将其从左侧拖入右侧文件夹中&#xff0c;等待安装完毕2、应用程序显示软件图标&#xff0c;表示安装成功 三、运行测试1、打开软件&#xff0c;进行设置2、下载视频&#xff0c;测试3、根据需要选…

关于unbuntu的终端自动退出的解决方案

输入sudo vim /etc/profile 将下面的TMOUT的时间注释掉 source /etc/profile使得更改生效

打破数据分析壁垒:SPSS复习必备(一)

一、数据录入与数据获取 1.变量的测量尺度 &#xff08;1&#xff09;定类尺度 顾名思义&#xff0c;是对事物的类别或属性的一种测度&#xff0c;按照事物的某种属性对其进行分类或分组。 该类变量只能计算频数和频率&#xff0c;用表示 &#xff08;2&#xff09;定序尺…

人生感悟 | 我们为什么贫穷?

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 我们为什么贫穷&#xff1f; 因为我们都在局中并坦然的按着规则制定者循规蹈矩的生活。 01 负债导致贫穷 最近同事买房&#xff0c;总价一百多万&#xff0c;月供四千多&#xff0c;讲话&#xff1a;已入坑&#xff0…

python反序列化知识点学习

最近遇到了python反序列化的题目&#xff0c;简单学习一下相关的知识点 基础知识 Python 的序列化指的是将 Python 对象转换为一种格式&#xff0c;以便可以将其存储在文件或通过网络传输。Python 中最常用的序列化模块是 pickle 模块。 序列化使用的是pickle.dumps方法&…

qt仿制qq登录界面

#include "mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) {// 设置窗口大小this->resize(window_width, window_heigth);// 固定窗口大小this->setFixedSize(window_width, window_heigth);// 设置窗口图标this->se…

JavaScript-数组

学习目标&#xff1a; 掌握数组 学习内容&#xff1a; 数组是什么数组的基本使用练习操作数组 数组是什么&#xff1a; 数组Array 是一种可以按顺序保存数据的数据类型。场景&#xff1a;如果有多个数据可以用数组保存起来&#xff0c;然后放到一个变量中&#xff0c;管理非常…

SQL 表连接(表关联)

目录 一、INNER JOIN&#xff08;内连接,等值连接&#xff09; 二、LEFT JOIN&#xff08;左连接&#xff09; 三、RIGHT JOIN&#xff08;右连接&#xff09;&#xff1a; 一、INNER JOIN&#xff08;内连接,等值连接&#xff09; 用途&#xff1a;获取两个表中字段能匹配上…