RT_thread(二)线程的操作

2023-10-30


重点

1.创建静态线程rt_thread_init——删除静态线程rt_thread_detach
创建动态线程rt_thread_create——删除静态线程rt_thread_delete
2.线程删除会判断线程是否为初始态,是则不删除,如何删除初始态线程?
3.线程不能写成死循环,必须有让出处理器的延时操作


一、线程是什么?

在 RT-Thread 中,任务对应的程序实体就是线程,线程是实现任务的载体,它是 RT-Thread 中最基本的调度单位,它描述了一个任务执行的运行环境,也描述了这个任务所处的优先等级,重要的任务可设置相对较高的优先级,非重要的任务可以设置较低的优先级,不同的任务还可以设置相同的优先级,轮流运行。

二、线程的工作机制

1.线程控制块

这是线程控制快的基本信息

在这里插入图片描述

/* 线程控制块 */
struct rt_thread
{
    /* rt 对象 */
    char        name[RT_NAME_MAX];      //线程名称
    rt_uint8_t  type;                   // 对象类型 
    rt_uint8_t  flags;                  // 标志位 

    rt_list_t   list;                   // 对象列表
    rt_list_t   tlist;                  // 线程列表 

    /* 栈指针与入口指针 */
    void       *sp;                      //栈指针
    void       *entry;                   //入口函数指针 
    void       *parameter;               //参数 
    void       *stack_addr;              //栈地址指针 
    rt_uint32_t stack_size;              //栈大小 

    /* 错误代码 */
    rt_err_t    error;                  //线程错误代码 
    rt_uint8_t  stat;                   // 线程状态 

    /* 优先级 */
    rt_uint8_t  current_priority;       //当前优先级 
    rt_uint8_t  init_priority;          //初始优先级 
    rt_uint32_t number_mask;

    ......

    rt_ubase_t  init_tick;              //线程初始化计数值 
    rt_ubase_t  remaining_tick;         //线程剩余计数值 

    struct rt_timer thread_timer;       //内置线程定时器 

    void (*cleanup)(struct rt_thread *tid);  //线程退出清除函数
    rt_uint32_t user_data;                      //用户数据 
};


2.线程API

1.思维图

在这里插入图片描述
在这里插入图片描述

2.创建静态线程

static rt_err_t _rt_thread_init(struct rt_thread *thread,
                                const char       *name,
                                void (*entry)(void *parameter),
                                void             *parameter,
                                void             *stack_start,
                                rt_uint32_t       stack_size,
                                rt_uint8_t        priority,
                                rt_uint32_t       tick)
{
    /* init thread list */
    rt_list_init(&(thread->tlist));//线程链表初始化

    thread->entry = (void *)entry;
    thread->parameter = parameter;

    /* stack init */
    thread->stack_addr = stack_start;//线程栈初始化
    thread->stack_size = stack_size;

    /* init thread stack */
    rt_memset(thread->stack_addr, '#', thread->stack_size);//将内存的内容设置为指定的值#
    thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
                                          (void *)((char *)thread->stack_addr + thread->stack_size - 4),
                                          (void *)rt_thread_exit);//sp指针放在栈顶

    /* priority init */
    RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);//检查优先级
    thread->init_priority    = priority;
    thread->current_priority = priority;

    thread->number_mask = 0;
#if RT_THREAD_PRIORITY_MAX > 32
    thread->number = 0;
    thread->high_mask = 0;
#endif

    /* tick init */
    thread->init_tick      = tick; //定时器初始化
    thread->remaining_tick = tick;

    /* error and flags */
    thread->error = RT_EOK;                    //标志位初始化
    thread->stat  = RT_THREAD_INIT;

    /* initialize cleanup function and user data */
    thread->cleanup   = 0;
    thread->user_data = 0;

    /* init thread timer */
    rt_timer_init(&(thread->thread_timer),
                  thread->name,
                  rt_thread_timeout,
                  thread,
                  0,
                  RT_TIMER_FLAG_ONE_SHOT);//线程定时器初始化

    /* initialize signal */
#ifdef RT_USING_SIGNALS
    thread->sig_mask    = 0x00;
    thread->sig_pending = 0x00;

    thread->sig_ret     = RT_NULL;
    thread->sig_vectors = RT_NULL;
    thread->si_list     = RT_NULL;
#endif

#ifdef RT_USING_LWP
    thread->lwp = RT_NULL;
#endif

    RT_OBJECT_HOOK_CALL(rt_thread_inited_hook, (thread));

    return RT_EOK;
}

3启动线程

rt_err_t rt_thread_startup(rt_thread_t thread)
{
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT);
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);//核查是否为线程并且是否符合线程规定

    /* set current priority to init priority */
    thread->current_priority = thread->init_priority;//系统当前优先级为初始优先级

    /* calculate priority attribute */
#if RT_THREAD_PRIORITY_MAX > 32
    thread->number      = thread->current_priority >> 3;            //优先级右移3位(除以8)(优先级大于32位的操作)
    thread->number_mask = 1L << thread->number;//long字型32位左移number位,制作掩码(优先级组数,一组32个优先级)
    thread->high_mask   = 1L << (thread->current_priority & 0x07);  //制作掩码(优先级数)
#else
    thread->number_mask = 1L << thread->current_priority;
#endif

    RT_DEBUG_LOG(RT_DEBUG_THREAD, ("startup a thread:%s with priority:%d\n",
                                   thread->name, thread->init_priority));
    /* change thread stat */
    thread->stat = RT_THREAD_SUSPEND;//rt_thread_resume只会恢复状态为susupend的线程
    /* then resume it */
    rt_thread_resume(thread);//将线程添加到就绪列表
    if (rt_thread_self() != RT_NULL)
    {
        /* do a scheduling */
        rt_schedule();
    }

    return RT_EOK;
}
RTM_EXPORT(rt_thread_startup);

4.静态线程脱离

rt_err_t rt_thread_detach(rt_thread_t thread)
{
    rt_base_t lock;

    /* thread check */
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);//检测类型状态
    RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread));

    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)//判断是否为初始态,如果是线程并未启动,不删除
    {
        /* remove from schedule */
        rt_schedule_remove_thread(thread);
    }

    /* release thread timer */
    rt_timer_detach(&(thread->thread_timer));//移除线程定时器

    /* change stat */
    thread->stat = RT_THREAD_CLOSE;//线程状态为关闭

    /* detach object */
    rt_object_detach((rt_object_t)thread);//对象移除

    if (thread->cleanup != RT_NULL)//线程没清理干净则插入僵尸线程链表
    {
        /* disable interrupt */
        lock = rt_hw_interrupt_disable();

        /* insert to defunct thread list */
        rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));

        /* enable interrupt */
        rt_hw_interrupt_enable(lock);
    }

    return RT_EOK;
}
RTM_EXPORT(rt_thread_detach);

5.创建动态线程

rt_thread_t rt_thread_create(const char *name,
                             void (*entry)(void *parameter),
                             void       *parameter,
                             rt_uint32_t stack_size,
                             rt_uint8_t  priority,
                             rt_uint32_t tick)
{
    struct rt_thread *thread;
    void *stack_start;

    thread = (struct rt_thread *)rt_object_allocate(RT_Object_Class_Thread,
                                                    name);              //创建对象
    if (thread == RT_NULL)
        return RT_NULL;

    stack_start = (void *)RT_KERNEL_MALLOC(stack_size);//分配内存
    if (stack_start == RT_NULL)
    {
        /* allocate stack failure */
        rt_object_delete((rt_object_t)thread);//未分配内存删除对象

        return RT_NULL;
    }

    _rt_thread_init(thread,
                    name,
                    entry,
                    parameter,
                    stack_start,
                    stack_size,
                    priority,
                    tick);

    return thread;
}
RTM_EXPORT(rt_thread_create);

6.动态线程删除

rt_err_t rt_thread_delete(rt_thread_t thread)
·1{
    rt_base_t lock;

    /* thread check */
    RT_ASSERT(thread != RT_NULL);//核查线程是否为空,检查类型
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
    RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread) == RT_FALSE);

    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)//判断是否为初始态,如果是线程并未启动,不删除
    {
        /* remove from schedule */
        rt_schedule_remove_thread(thread);
    }

    /* release thread timer */
    rt_timer_detach(&(thread->thread_timer));//移除线程定时器

    /* change stat */
    thread->stat = RT_THREAD_CLOSE;//状态设置为关闭

    /* disable interrupt */
    lock = rt_hw_interrupt_disable();//关中断1

    /* insert to defunct thread list */
    rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));//插入僵尸队列

    /* enable interrupt */
    rt_hw_interrupt_enable(lock);//开中断1

    return RT_EOK;
}
RTM_EXPORT(rt_thread_delete);
#endif

7.使线程让出处理器资源

rt_err_t rt_thread_yield(void)
{
    register rt_base_t level;
    struct rt_thread *thread;

    /* disable interrupt */
    level = rt_hw_interrupt_disable();//关中断1

    /* set to current thread */
    thread = rt_current_thread;//获得当前线程

    /* if the thread stat is READY and on ready queue list */
    if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY &&
        thread->tlist.next != thread->tlist.prev)//判断获得线程是否位于就绪链表第一个
    {
        /* remove thread from thread list */
        rt_list_remove(&(thread->tlist));//移除就绪链表

        /* put thread to end of ready queue */
        rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
                              &(thread->tlist));        //重新插入就绪链表

        /* enable interrupt */
        rt_hw_interrupt_enable(level);//开中断1

        rt_schedule();

        return RT_EOK;
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(level);//开中断1

    return RT_EOK;
}
RTM_EXPORT(rt_thread_yield);

8.使线程休眠几个节拍

rt_err_t rt_thread_sleep(rt_tick_t tick)
{
    register rt_base_t temp;
    struct rt_thread *thread;

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();//关中断1
    /* set to current thread */
    thread = rt_current_thread;
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);

    /* suspend thread */
    rt_thread_suspend(thread);//挂起线程

    /* reset the timeout of thread timer and start it */
    rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick);//重置延时节拍参数
    rt_timer_start(&(thread->thread_timer));//开启线程定时器

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);//开中断1

    rt_schedule();

    /* clear error number of this thread to RT_EOK */
    if (thread->error == -RT_ETIMEOUT)//错误号修正
        thread->error = RT_EOK;

    return RT_EOK;
}

9.线程节拍延时

rt_err_t rt_thread_delay(rt_tick_t tick)
{
    return rt_thread_sleep(tick);//效果一样
}
RTM_EXPORT(rt_thread_delay);

10.线程毫秒延时

rt_err_t rt_thread_mdelay(rt_int32_t ms)
{
    rt_tick_t tick;

    tick = rt_tick_from_millisecond(ms);//换算下ms到节拍

    return rt_thread_sleep(tick);
}
RTM_EXPORT(rt_thread_mdelay);

11.修改线程参数

rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg)
{
    register rt_base_t temp;

    /* thread check */
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);

    switch (cmd)//接收指令,并运行
    {
    case RT_THREAD_CTRL_CHANGE_PRIORITY://改变线程优先级
        /* disable interrupt */
        temp = rt_hw_interrupt_disable();

        /* for ready thread, change queue */
        if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY)
        {
            /* remove thread from schedule queue first */
            rt_schedule_remove_thread(thread);

            /* change thread priority */
            thread->current_priority = *(rt_uint8_t *)arg;

            /* recalculate priority attribute */
#if RT_THREAD_PRIORITY_MAX > 32                                     //优先级参数是否合法判断
            thread->number      = thread->current_priority >> 3;            /* 5bit */
            thread->number_mask = 1 << thread->number;
            thread->high_mask   = 1 << (thread->current_priority & 0x07);   /* 3bit */
#else
            thread->number_mask = 1 << thread->current_priority;
#endif

            /* insert thread to schedule queue again */
            rt_schedule_insert_thread(thread);
        }
        else
        {
            thread->current_priority = *(rt_uint8_t *)arg;

            /* recalculate priority attribute */
#if RT_THREAD_PRIORITY_MAX > 32
            thread->number      = thread->current_priority >> 3;            /* 5bit */
            thread->number_mask = 1 << thread->number;
            thread->high_mask   = 1 << (thread->current_priority & 0x07);   /* 3bit */
#else
            thread->number_mask = 1 << thread->current_priority;
#endif
        }

        /* enable interrupt */
        rt_hw_interrupt_enable(temp);
        break;

    case RT_THREAD_CTRL_STARTUP://开启线程
        return rt_thread_startup(thread);

#ifdef RT_USING_HEAP
    case RT_THREAD_CTRL_CLOSE://删除线程
        return rt_thread_delete(thread);
#endif

    default:
        break;
    }

    return RT_EOK;
}
RTM_EXPORT(rt_thread_control);

12.挂起线程

rt_err_t rt_thread_suspend(rt_thread_t thread)
{
    register rt_base_t temp;

    /* thread check */
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);

    RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend:  %s\n", thread->name));

    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_READY)//线程不是就绪状态发送当前状态日志
    {
        RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: thread disorder, 0x%2x\n",
                                       thread->stat));

        return -RT_ERROR;
    }

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();//关中断1

    /* change thread stat */
    thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK);//设置线程标志位
    rt_schedule_remove_thread(thread);//调度器移除线程

    /* stop thread timer anyway */
    rt_timer_stop(&(thread->thread_timer));//关闭线程定时器

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);//开中断1

    RT_OBJECT_HOOK_CALL(rt_thread_suspend_hook, (thread));
    return RT_EOK;
}
RTM_EXPORT(rt_thread_suspend);

13.恢复挂起线程

rt_err_t rt_thread_resume(rt_thread_t thread)
{
    register rt_base_t temp;

    /* thread check */
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);

    RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume:  %s\n", thread->name));

    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND)
    {
        RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: thread disorder, %d\n",
                                       thread->stat));

        return -RT_ERROR;
    }

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();//开中断1

    /* remove from suspend list */
    rt_list_remove(&(thread->tlist));//线程挂起队列中移除

    rt_timer_stop(&thread->thread_timer);//停止线程定时器

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);//开中断1

    /* insert to schedule ready list */
    rt_schedule_insert_thread(thread);//将线程

    RT_OBJECT_HOOK_CALL(rt_thread_resume_hook, (thread));
    return RT_EOK;
}
RTM_EXPORT(rt_thread_resume);

14.线程超时等待资源使用

void rt_thread_timeout(void *parameter)
{
    struct rt_thread *thread;

    thread = (struct rt_thread *)parameter;

    /* thread check */
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND);
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);

    /* set error number */
    thread->error = -RT_ETIMEOUT;//为什么设置为负数???

    /* remove from suspend list */
    rt_list_remove(&(thread->tlist));//线程移出队列

    /* insert to schedule ready list */
    rt_schedule_insert_thread(thread);//线程加入就绪链表

    /* do schedule */
    rt_schedule();//启动调度器
}
RTM_EXPORT(rt_thread_timeout);

15.查找线程

rt_thread_t rt_thread_find(char *name)
{
    struct rt_object_information *information;
    struct rt_object *object;
    struct rt_list_node *node;

    /* enter critical */
    if (rt_thread_self() != RT_NULL)
        rt_enter_critical();      //打开调度锁

    /* try to find device object */
    information = rt_object_get_information(RT_Object_Class_Thread);//获得线程对象(储存再对象容器中)结构体参数
    RT_ASSERT(information != RT_NULL);
    for (node  = information->object_list.next;           //对象链表中遍历
         node != &(information->object_list);
         node  = node->next)
    {
        object = rt_list_entry(node, struct rt_object, list);//取出对象节点参数
        if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
        {
            /* leave critical */
            if (rt_thread_self() != RT_NULL)
                rt_exit_critical();//关调度锁并返回找到线程

            return (rt_thread_t)object;
        }
    }

    /* leave critical */
    if (rt_thread_self() != RT_NULL)
        rt_exit_critical();   //关调度锁并返回未找到

    /* not found */
    return RT_NULL;
}
RTM_EXPORT(rt_thread_find);

16.空闲线程

空闲线程是一个线程状态永远为就绪态的线程


3. rtthread例程下载

https://gitee.com/rtthread/docs-online/raw/master/rt-thread-version/rt-thread-standard/tutorial/quick-start/stm32f103-simulator/rtthread_simulator_v0.1.0.7z
例程来源链接https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/tutorial/quick-start/stm32f103-simulator/stm32f103-simulator?id=%e5%85%b6%e4%bb%96%e4%be%8b%e5%ad%90

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

RT_thread(二)线程的操作 的相关文章

  • 错误:GitHub 目前无法显示这么大的文件 - 但该文件只有 1.06 MB [已关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 我通过两种不同的方式将 HTML 文件上传到 GitHub 存储库 拖放以及使用终端上的 Git 添加 提交 推送 在这两种情况下
  • git rebase -i ——为什么它改变提交哈希值?

    所以我或多或少熟悉变基的工作原理 但直到最近我通常只做了一个git rebase i HEAD 20 并修改了需要修改的内容 我很惊讶地发现这将修改所有 20 个提交的哈希值 即使我采取的唯一操作是压缩最后两个提交 我不确定是什么导致其他
  • 从 git 签出后 nuget dll 丢失

    I have a C solution containing different projects On those projects I have some normal nuget packages like Newtonsoft Js
  • 我有*很多*源文件要添加到 git 存储库,如何使其快速

    我在看here https git scm com docs git fast import寻找更快地将批量文件导入 git 存储库的灵感 但不确定是不是这样 基本上情况是 我有超过 1 亿个文件想要提交到 git 存储库 我已将它们分解为
  • 如何在 git 中删除 subversion 远程?

    我有一个最初使用 git svn 创建的 git 存储库 现在我有一个推送到的 git 服务器 但 svn 存储库已丢失 我可以删除 svn 远程吗 如何 您可以编辑 git config文件并删除与要删除的遥控器关联的部分 您要删除的行可
  • git push origin 分支名总是推送到 master

    我搜索了一下 但似乎找不到答案 在我可以访问的两个盒子上 当我执行 git push dry run origin mytestbranch 时 我得到以下结果 To email protected cdn cgi l email prot
  • Git 显示更改后的相同文件

    当我似乎无法弄清楚更改时 Git 向我显示整个文件已更改 这是 cygwin git 但它也发生在 msysgit 中 git version git version 2 1 1 diff lt git show HEAD File cs
  • 如何在 git diff 中按标点符号拆分单词?

    我对以下命令有一些运气 git diff color words lt gt space lt gt 但它似乎没有在第一个字符类中正确地否定方括号 我试过这个 git diff color words lt gt space lt gt 为
  • GIT 中的重复合并。它如何计算差异?

    我一直在做一项研究 试图了解 GIT 合并是如何工作的 我知道有几种合并类型 如递归 章鱼等 我发现解析 递归是最常用的 并且递归合并仅在存在多个共同祖先 基础时才有用 但是 我找不到从分支重复合并到主节点时使用哪种算法 或者如何计算祖先
  • 如何预览 Git 中的隐藏内容?

    我想检查一个存储 并找出如果我将其应用于当前状态的工作树 它会发生什么变化 我知道我可以对存储进行 git diff 但这向我展示了工作树和存储之间的所有差异 而我只是想知道存储应用将改变什么 git stash show将向您显示最近存储
  • 在两个单独的分支或存储库中管理项目后端和前端?

    我启动了一个移动应用程序项目 该项目将具有服务器端和应用程序本身 所以 在master分支我创建了2个项目myapp server and myapp然后我创建了另外 2 个分支backend and frontend我只想将与它们相对应的
  • Git 子模块:[电子邮件受保护]:权限被拒绝(公钥)。致命:无法从远程存储库读取

    我有一个问题git submodule update init remote 我收到错误 权限被拒绝和克隆失败 但我将 SSH 密钥添加到了我的 github 存储库中 我可以拉 推 git 克隆 我拥有所有需要的访问权限 我使用操作系统
  • 为什么cherry-pick总是会导致合并冲突?

    我正在从发布分支中挑选特定的提交到我的本地工作副本中 每次我从发布分支中挑选一个提交时 我都会遇到必须解决的合并冲突 即使更改看起来微不足道 例如 const char kApplicationVersion Develop const c
  • 在 git 子模块中签出分支

    如何从子模块内更改分支 当我跑步时git branch从子模块内 我看到以下输出 gt git branch HEAD detached from 229a7b2 master 我如何将自己置于一个新的分支上 喜欢development 只
  • 交互式变基后,本地 Git 分支已偏离原始分支

    我有一个本地分行 CRM ayrshireminis 其中有一些我已推送到原点的提交 origin CRM ayrshireminis 这个分支是从创建的develop大约一周前的一个分支 其他合作者已经在该分支上完成了一周的工作 我想做的
  • 有没有办法缓存 https 凭据以推送提交?

    我最近转而将我的存储库同步到 GitHub 上的 https 由于防火墙问题 并且每次都要求输入密码 有没有办法缓存凭据 而不是每次都进行身份验证git push 自 Git 1 7 9 2012 年发布 以来 Git 中有一个巧妙的机制可
  • 在 git repo 中查找超过 x MB 且 HEAD 中不存在的文件

    我有一个 Git 存储库 用于存储随机的内容 主要是随机脚本 文本文件 我设计的网站等 随着时间的推移 我删除了一些大型二进制文件 通常为 1 5MB 这些文件会增加存储库的大小 而我在修订历史记录中不需要这些文件 基本上我希望能够做到 m
  • DVCS命令的统一

    当处理多个 开源 项目时 多个版本控制系统开始出现问题 虽然它们共享共同的操作 但我经常在输入时犯错误hg add反而git add 我记得前段时间看到过一个项目 通过提供基本命令以统一的方式访问不同的源代码控制软件提交 ci add等在外
  • git 预提交钩子格式代码 - Intellij/Android Studio

    本要点展示了如何在预提交时使用 Eclipse 格式化程序自动格式化 Java 代码 Source https gist github com ktoso 708972 https gist github com ktoso 708972
  • 无法使用 git 配置文件进行 ssh

    我知道它被问了很多次 但我无法得到我的问题的答案 我正在尝试使用配置文件 ssh 到系统 配置文件是 Host qa HostName 10 218 70 345 User user IdentityFile C Users bean ss

随机推荐

  • 5G赋能智慧城市白皮书 附下载地址

    随着经济社会的快速发展和加速转型 传统城市管理模式的局限性日益显现 随着全球城市化 进程的加快 为了应对人口 资源 环境等对城市发展的挑战 全球各国都以 智慧城市 建 设作为全新的城市发展理念和实践路径 而传统智慧城市建设中 由于细分智慧应
  • 应用层——电子邮件(SMTP、POP3、IMAP)

    目录 1 电子邮件系统及组成结构 1 1 电子邮件 1 2 电子邮件系统的组件 2 SMTP 邮件发送协议 2 1 SMTP的特征 2 2 SMTP的基本操作 2 3 SMTP协议的基本流程 2 4 SMTP交互与应答 2 5 SMTP与H
  • 预测性维护

    1 预测性维护 1 1 介绍 预见性维护 PdM 承诺在工厂车间达到前所未有的效率和安全水平 目前已建立的系统和流程的最佳实践 机器停机是生产线上最大的挑战之一 目前的MRO 维护 维修 操作 方法远未达到最佳生产水平 通过预测性维护 一旦
  • kettle对接hive

    kettle没有自带hive的驱动 如果在界面上直接选Hadoop Hive 2 3会报找不到驱动的错误 按照网上的解决方案修改了plugins文件夹里的配置文件后仍然无法解决 还是需要把驱动jar放入kettle里才可以 docker c
  • C++:多线程的正确打开姿势

    目的 本例简介c 11中thread库如何创建与停止线程 实现 如下的实例中 通过ThreadWrapper start 方法启动线程 通过ThreadWrapper stop 方法停止线程 线程的主体函数为Thread run 方法 in
  • Servlet 基础知识及操作

    一 什么是servlet Servlet Server Applet 是Java Servlet的简称 称为小服务程序或服务连接器 用Java编写的服务器端程序 具有独立于平台和协议的特性 主要功能在于交互式地浏览和生成数据 生成动态Web
  • [POI2008]CLO-Toll

    题目链接 本题有个小点需要注意 如果说它是多个相互不连通的图 也有可能形成一个可行解 多个环嘛 然后剩下的 就是dfs去跑 如果跑出了返祖边 那么这个返祖边抵达的点 将改变原来的方向 剩下的就都是正方向 dfs直接跑就是了 include
  • 【回溯法】n皇后问题并输出每种解的情况 C语言版

    问题描述 在n n的方格棋盘上 放置n个皇后 要求 个皇后两两不在一行 不在一列 不在同一对角线上 PS 行不用检测 因为皇后本身就是一行一行往下放的 并且一行只能放一个 所以当放好一个皇后后 只需检测列及对角线的位置有无皇后 如下图这些位
  • 报告论文:手写数字识别

    手写数字识别 简单手写数字识别系统 我们对VC比较熟悉 采用VC开发 数字的类别只有十种 笔划又简单 其识别问题似乎不是很困难 但事实上 一些测试结果表明 数字的正确识别率并不如印刷体汉字识别正确率高 甚至也不如联机手写体汉字识别率高 而只
  • 服务器的线路有很多

    服务器的线路有很多 大致的分为 CN2 CIA CDIA GIA等 首先简单介绍一下什么是IPLC专线 IPLC专线是国际私用出租线路 本质就是点对点内网 网络的入口在国内 所以不会受 国际链路影响 也不用走国家防火墙 IP地址可用率高 不
  • 怎么在外部类外访问内部类

    在外部类外访问内部类 Wai Nei wn new Wai new Nei 上式相当于 Wai w new Wai Wai Nei wn w new Nei package a class Wai class Nei int i 5 int
  • 【自然语言处理】利用TextRank算法提取关键词

    利用TextRank提取关键词 TextRank 是一种基于 PageRank 的算法 常用于关键词提取和文本摘要 在本文中 我将通过一个关键字提取示例帮助您了解 TextRank 如何工作 并展示 Python 的实现 使用 TextRa
  • MySQL按逗号拆分列为多行

    图一 图二 按逗号拆分列为多行 把 图一 的展示效果转换成 图二 的展示效果 1 创建用户表 sys user CREATE TABLE sys user id BIGINT NOT NULL auto increment COMMENT
  • 工厂方法模式与抽象工厂模式

    工厂方法模式与抽象工厂模式 一 工厂方法模式 Factory Method 解决的问题 案例 实现步骤 代码示例 比较冗余 只是看设计模式的思想 根据案例分析工厂方法模式 JDK源码中的工厂方法模式 二 抽象工厂模式 Abstract Fa
  • (附源码)vue3.0+.NET6实现聊天室(实时聊天SignalR)

    参考文章 搭建文章 gitte源码 在线体验 可以注册两个号来测试 演示图 一 整体介绍 介绍SignalR一种通讯模型Hub 中心模型 或者叫集线器模型 调用这个模型写好的方法 去发送消息 内容有 Hub模型的方法介绍 服务器端代码介绍
  • Webpack详解

    零 文章目录 Webpack详解 1 webpack基本概念 1 webpack是什么 静态模块打包工具 官网 https webpack docschina org 官网文档 https webpack docschina org con
  • selenium 淘宝爬虫(需要扫码登录一下)

    from selenium import webdriver import time import re def gethtml url 定义函数获取html源代码 由于淘宝是动态网页无法用requests库获取所以使用selenium模拟
  • Signature expired

    django 中使用itsdangerous加密时会出现 Signature expired 签名过期的问题 解决办法 expires in设置时间稍微长一点 然后重启pycharm 重新打开项目 比如设置expires in 3600 单
  • AI+林业重塑未来,科技力量守护森林生态宝

    引言 在科技日新月异的时代 人工智能 AI 作为一项崭新的技术 正在革新着我们社会的方方面面 素有 地球之肺 美誉的森林作为人类生存发展中不可或缺的一部分 其管理与保护也开始融入AI技术 催生出了AI 林业这一新兴领域 在AI 林业的浪潮中
  • RT_thread(二)线程的操作

    文章目录 重点 一 线程是什么 二 线程的工作机制 1 线程控制块 2 线程API 1 思维图 2 创建静态线程 3启动线程 4 静态线程脱离 5 创建动态线程 6 动态线程删除 7 使线程让出处理器资源 8 使线程休眠几个节拍 9 线程节