POSIX线程(二)

news2024/9/23 19:21:39

目录

一、前言

二、Thread Attributes

1、Setting the Detached State Attribute(thread5.c)

2、Thread Attributes Scheduling 

(1)Scheduling(thread6.c)

三、Canceling a Thread

1、Canceling a Thread(thread7.c)

四、Threads in Abundance

1、Many Threads(thread8.c)


一、前言

在上一板块“进程与信号”中,我们了解了如何在 Linux ( 以及 UNIX ) 中处理进程。这些多处理特性一直是类 unix 操作系统的一个特性。有时,让一个程序同时做两件事可能非常有用,或者至少看起来是这样做的,或者我们可能希望两件或更多的事情以紧密耦合的方式同时发生,但考虑到使用 fork 创建新进程的开销太大。对于这些情况,我们可以使用线程,它允许单个进程执行多任务。

下面我们将学习到:

❑ Creating new threads within a process

❑ Synchronizing data access between threads in a single process

❑ Modifying the attributes of a thread

❑ Controlling one thread from another in the same process

二、Thread Attributes

当我们第一次讨论线程时,我们没有讨论线程属性这个更高级的主题。既然我们已经讨论了同步线程的关键主题,那么我们可以回过头来看看线程本身的这些更高级的特性。线程有相当多的属性可以控制,在这里,我们只看那些你最有可能需要的。你可以在手册页面中找到其他的详细信息。

在前面的所有示例中,在允许程序退出之前,必须使用 pthread_join 重新同步线程。如果希望允许一个线程将数据返回给创建数据的线程,则需要这样做。有时,你既不需要第二个线程向主线程返回信息,也不希望主线程等待它。

假设在主线程继续为用户服务的同时,你创建了第二个线程来脱机正在编辑的数据文件的备份副本。备份完成后,第二个线程就可以终止了。它不需要重新连接主线程。

你可以创建这样的线程。它们被称为分离线程,可以通过修改线程属性或调用 pthread_detach 来创建它们。因为我们想要演示属性,所以我们在这里使用前一种方法。

你需要的最重要的函数是 pthread_attr_init,它初始化线程属性对象。

同样,成功时返回 0,失败时返回错误代码。 

还有一个 destroy 函数:pthread_attr_destroy。它的目的是允许清除属性对象。一旦对象被销毁,它就不能再被使用,直到它被重新初始化。

初始化线程属性对象后,可以调用许多附加函数来设置不同的属性行为。我们在这里列出了主要的函数 (也可以在手册页中找到完整的列表,通常在 pthread.h 下面的条目),但只仔细看两个,detachedstate 和 schedpolicy:

正如你所看到的,有相当多的属性可以使用,但幸运的是,你通常不需要使用其中的大多数属性。

❑ detachedstate:此属性允许你避免需要重新连接线程。与大多数 these_set 函数一样,它接受一个指向属性的指针和一个标志来确定所需的状态。pthread_attr_setdetachstate 的两个可能标志值是 PTHREAD_CREATE_JOINABLE 和 PTHREAD_CREATE_DETACHED。默认情况下,该属性的值为 PTHREAD_CREATE_JOINABLE,这样你就可以允许两个线程连接。如果状态设置为 PTHREAD_CREATE_DETACHED,则不能调用 pthread_join 来恢复另一个线程的退出状态。

❑ schedpolicy:它控制如何调度线程。选项包括 SCHED_OTHER、SCHED_RP 和 SCHED_FIFO。默认情况下,该属性为 SCHED_OTHER。另外两种调度类型仅对具有超级用户权限的进程可用,因为它们都具有实时调度,但行为略有不同。SCHED_RR 使用 roundrobin 调度方案,SCHED_FIFO 使用“先进先出”策略。

❑ schedparam:这是 schedpolicy 的一部分,允许控制使用调度策略 SCHED_OTHER 运行的线程的调度。在后面我们会看到一个这样的例子。

❑ inheritsched:该属性有两个可能的值:PTHREAD_EXPLICIT_SCHED 和 PTHREAD_INHERIT_SCHED。默认情况下,该值是 PTHREAD_EXPLICIT_SCHED,这意味着调度是由属性显式设置的。通过将其设置为 PTHREAD_INHERIT_SCHED,新线程将使用其创建线程正在使用的参数。

❑ scope:此属性控制如何计算线程的调度。因为 Linux 目前只支持值 PTHREAD_SCOPE_SYSTEM,我们在这里不再深入讨论。

❑ stacksize:该属性控制线程创建堆栈的大小,以字节为单位设置。这是规范“可选”部分的一部分,仅在定义了 POSIX THREAD_ATTR_STACKSIZE 的实现中得到支持。Linux 在默认情况下实现了具有大量堆栈的线程,因此该特性在 Linux 上通常是多余的。

1、Setting the Detached State Attribute(thread5.c)

对于分离线程示例 thread5.c,你创建一个线程属性,将其设置为分离,然后使用该属性创建一个线程。现在,当子线程完成时,它以正常的方式调用 pthread_exit 。然而,这一次,初始线程不再等待它创建的线程重新加入。在本例中,你使用一个简单的 thread_finished 标志来允许主线程检测子进程是否已经完成,并显示线程仍然在共享变量。

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

void *thread_function(void *arg);

char message[] = "Hello World";
int thread_finished = 0;

int main() {
    int res;
    pthread_t a_thread;
    void *thread_result;
    pthread_attr_t thread_attr;

    res = pthread_attr_init(&thread_attr);
    if (res != 0) {
        perror("Attribute creation failed");
        exit(EXIT_FAILURE);
    }
    res = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
    if (res != 0) {
        perror("Setting detached attribute failed");
        exit(EXIT_FAILURE);
    }
    res = pthread_create(&a_thread, &thread_attr, thread_function, (void *)message);
    if (res != 0) {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }
    (void)pthread_attr_destroy(&thread_attr);
    while(!thread_finished) {
        printf("Waiting for thread to say it's finished...\n");
        sleep(1);
    }
    printf("Other thread finished, bye!\n");
    exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {
    printf("thread_function is running. Argument was %s\n", (char *)arg);
    sleep(4);
    printf("Second thread setting finished flag, and exiting now\n");
    thread_finished = 1;
    pthread_exit(NULL);
}

可以看到,设置分离状态允许次要线程独立完成,而不需要初始线程等待它。

How It Works:

代码的两个重要部分是:

声明一个线程属性并初始化它,同时:

它将属性值设置为具有分离状态。 

其他细微的区别是创建线程,传递属性的地址,

并且,为了完整性,当你使用了属性时,销毁它们: 

2、Thread Attributes Scheduling 

让我们看看你可能希望更改的第二个线程属性:调度。更改调度属性非常类似于设置分离状态,但是还有两个函数可以用于查找可用的优先级级别,即 sched_get priority_max 和 sched_get priority_min。

(1)Scheduling(thread6.c)

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

void *thread_function(void *arg);

char message[] = "Hello World";
int thread_finished = 0;

int main() {
    int res;
    pthread_t a_thread;
    void *thread_result;
    pthread_attr_t thread_attr;

    int max_priority;
    int min_priority;
    struct sched_param scheduling_value;

    res = pthread_attr_init(&thread_attr);
    if (res != 0) {
        perror("Attribute creation failed");
        exit(EXIT_FAILURE);
    }
    res = pthread_attr_setschedpolicy(&thread_attr, SCHED_OTHER);
    if (res != 0) {
        perror("Setting schedpolicy failed");
        exit(EXIT_FAILURE);
    }
    res = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
    if (res != 0) {
        perror("Setting detached attribute failed");
        exit(EXIT_FAILURE);
    }
    res = pthread_create(&a_thread, &thread_attr, thread_function, (void *)message);
    if (res != 0) {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }
    max_priority = sched_get_priority_max(SCHED_OTHER);
    min_priority = sched_get_priority_min(SCHED_OTHER);
    scheduling_value.sched_priority = min_priority;
    res = pthread_attr_setschedparam(&thread_attr, &scheduling_value);
    if (res != 0) {
        perror("Setting schedpolicy failed");
        exit(EXIT_FAILURE);
    }
    (void)pthread_attr_destroy(&thread_attr);
    while(!thread_finished) {
        printf("Waiting for thread to say it's finished...\n");
        sleep(1);
    }
    printf("Other thread finished, bye!\n");
    exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {
    printf("thread_function is running. Argument was %s\n", (char *)arg);
    sleep(4);
    printf("Second thread setting finished flag, and exiting now\n");
    thread_finished = 1;
    pthread_exit(NULL);
}

How It Works:

这与设置分离状态属性非常相似,不同之处在于你设置的是调度策略。

三、Canceling a Thread

有时,你希望一个线程能够请求另一个线程终止,就像向它发送信号一样。对于线程,有一种方法可以做到这一点,并且与信号处理并行,线程可以在被要求终止时修改它们的行为。

让我们首先看一下请求线程终止的函数:

这非常简单:给定一个线程标识符,你可以请求取消它。在取消请求的接收端,情况稍微复杂一些,但也不是很多。线程可以使用 pthread_setcancelstate 设置其取消状态。

第一个参数是 PTHREAD_CANCEL_ENABLE,它允许它接收取消请求,或者 PTHREAD_CANCEL _DISABLE,它导致它们被忽略。oldstate 指针允许检索以前的状态。如果不感兴趣,可以简单地传递 NULL。如果接受取消请求,则线程可以获得第二级控制,即取消类型,该类型通过 pthread_setcanceltype 设置。 

该类型可以接受两个值中的一个:PTHREAD_CANCEL_ASYNCHRONOUS,它使取消请求立即被处理;PTHREAD_CANCEL_DEFERRED,它使取消请求等待,直到线程执行以下函数之一:pthread_join、pthread_cond_wait、pthread_cond_timedwait、pthread_testcancel、sem_wait或sigwait。 

我们没有涵盖所有这些调用,因为并非所有调用都是通常需要的。与以往一样,可以在手册页中找到更多的细节。

根据 POSIX 标准,其他可能阻塞的系统调用 (如读取、等待等) 也应该是取消点。在撰写本文时,Linux 中对此的支持似乎还不完全。然而,一些实验确实表明,一些被屏蔽的电话,如睡眠,确实允许取消发生。为了安全起见,你可能需要在您希望取消的代码中添加一些 pthread_testcancel 调用。

同样,oldtype 允许检索以前的状态,如果你对知道以前的状态不感兴趣,则可以传递 NULL。默认情况下,线程以取消状态PTHREAD_CANCEL_ENABLE和取消类型 PTHREAD_CANCEL_DEFERRED 开始。

1、Canceling a Thread(thread7.c)

程序 thread7.c 同样派生自 thread1.c。这一次,主线程向它所创建的线程发送一个取消请求。

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

void *thread_function(void *arg);

int main() {
    int res;
    pthread_t a_thread;
    void *thread_result;

    res = pthread_create(&a_thread, NULL, thread_function, NULL);
    if (res != 0) {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }
    sleep(3);
    printf("Canceling thread...\n");
    res = pthread_cancel(a_thread);
    if (res != 0) {
        perror("Thread cancelation failed");
        exit(EXIT_FAILURE);
    }
    printf("Waiting for thread to finish...\n");
    res = pthread_join(a_thread, &thread_result);
    if (res != 0) {
        perror("Thread join failed");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {
    int i, res, j;
    res = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    if (res != 0) {
        perror("Thread pthread_setcancelstate failed");
        exit(EXIT_FAILURE);
    }
    res = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
    if (res != 0) {
        perror("Thread pthread_setcanceltype failed");
        exit(EXIT_FAILURE);
    }
    printf("thread_function is running\n");
    for(i = 0; i < 10; i++) {
        printf("Thread is still running (%d)...\n", i);
        sleep(1);
    }
    pthread_exit(0);
}

How It Works:

在以通常的方式创建新线程之后,主线程休眠 (给新线程一些时间启动),然后发出一个取消请求:

在创建的线程中,首先设置 cancel 状态允许取消:

然后你设置取消类型为延迟:

最后,线程等待被取消:

四、Threads in Abundance

到目前为止,我们总是让程序执行的正常线程只创建另一个线程。但是,我们不希望你认为只能创建一个额外的线程。

1、Many Threads(thread8.c)

下面看最后一个例子thread8.c,我们将展示如何在同一个程序中创建几个线程,然后以不同于它们开始时的顺序再次收集它们。

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

#define NUM_THREADS 6

void *thread_function(void *arg);

int main() {
    int res;
    pthread_t a_thread[NUM_THREADS];
    void *thread_result;
    int lots_of_threads;

    for(lots_of_threads = 0; lots_of_threads < NUM_THREADS; lots_of_threads++) {

        res = pthread_create(&(a_thread[lots_of_threads]), NULL, thread_function, (void *)&lots_of_threads);
        if (res != 0) {
            perror("Thread creation failed");
            exit(EXIT_FAILURE);
        }
        sleep(1);
    }
    printf("Waiting for threads to finish...\n");
    for(lots_of_threads = NUM_THREADS - 1; lots_of_threads >= 0; lots_of_threads--) {
        res = pthread_join(a_thread[lots_of_threads], &thread_result);
        if (res == 0) {
            printf("Picked up a thread\n");
        }
        else {
            perror("pthread_join failed");
        }
    }
    printf("All done\n");
    exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {
    int my_number = *(int *)arg;
    int rand_num;

    printf("thread_function is running. Argument was %d\n", my_number);
    rand_num=1+(int)(9.0*rand()/(RAND_MAX+1.0));
    sleep(rand_num);
    printf("Bye from %d\n", my_number);
    pthread_exit(NULL);
}

如你所见,你创建了许多线程,并允许它们不按顺序完成。这个程序中有一个微妙的错误,如果从启动线程的循环中删除对 sleep 的调用,这个错误就会很明显。我们将它包含进来是为了向你展示在编写使用线程的程序时需要多么小心。我们将在下面解释。

这次你创建了一个线程 id 数组:

循环创建几个线程:

线程本身在退出前等待一个随机的时间:

而在主线程 (原始) 中,你等待取它们,但不是按照你创建它们的顺序: 

如果你试图在没有睡眠的情况下运行程序,可能会看到一些奇怪的效果,包括一些线程以相同的参数启动;例如,你可能会看到类似这样的输出:

你知道为什么会发生这种情况吗?线程使用局部变量作为线程函数的参数启动。这个变量在循环中更新。违规的行是:

如果主线程运行得足够快,它可能会改变某些线程的参数 (lots_of_threads)。当对共享变量和多个执行路径不够注意时,就会出现这样的行为。编程线程需要在设计时格外注意!要纠正这个问题,你需要像这样直接传递值:

当然还要改变thread_function:

这在程序 thread8a.c 中显示,并突出显示了更改:

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

#define NUM_THREADS 6

void *thread_function(void *arg);

int main() {
  
  int res;
  pthread_t a_thread[NUM_THREADS];
  void *thread_result;
  int lots_of_threads;
  

  for(lots_of_threads = 0; lots_of_threads < NUM_THREADS; lots_of_threads++) {

    /*modify*/
    res = pthread_create(&(a_thread[lots_of_threads]), NULL, thread_function, (void *)lots_of_threads);
    if (res != 0) {
      perror("Thread creation failed");
      exit(EXIT_FAILURE);
    }
    /*modify*/
    /*    sleep(1); */
  }

  printf("Waiting for threads to finish...\n");
  for(lots_of_threads = NUM_THREADS - 1; lots_of_threads >= 0; lots_of_threads--) {
    res = pthread_join(a_thread[lots_of_threads], &thread_result);
    if (res == 0) {
      printf("Picked up a thread\n");
    } else {
      perror("pthread_join failed");
    }
  }

  printf("All done\n");
  
  exit(EXIT_SUCCESS);
}

/*modify*/
void *thread_function(void *arg) {
    int my_number = (int)arg;
/*modify*/
    int rand_num;

    printf("thread_function is running. Argument was %d\n", my_number);
    rand_num=1+(int)(9.0*rand()/(RAND_MAX+1.0));
    sleep(rand_num);
    printf("Bye from %d\n", my_number);
    
    pthread_exit(NULL);
}




POSIX线程到此我们学习了如何在一个进程中创建多个执行线程,其中每个线程共享文件作用域变量。了解了线程可以使用信号量和互斥锁控制对关键代码和数据的访问的两种方式。接下来,了解了如何控制线程的属性,特别是如何将它们与主线程分离,以便主线程不再需要等待它创建的线程完成。在快速查看了一个线程如何请求另一个线程完成任务以及接收线程如何管理这些请求之后,我们给出了一个同时执行多个线程的程序示例。我们没有足够的篇幅来介绍所有与线程相关的函数调用和细微差别,但是我现在应该已经充分了解如何开始使用线程编写自己的程序,并通过阅读手册来研究线程更深奥的方面。

以上,POSIX线程(二)

祝好

 

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

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

相关文章

[附源码]计算机毕业设计医院门诊管理信息系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

一篇打通线程 等待 中断

✨✨hello&#xff0c;愿意点进来的小伙伴们&#xff0c;你们好呐&#xff01; &#x1f43b;&#x1f43b;系列专栏&#xff1a;【JavaEE初阶】 &#x1f432;&#x1f432;本篇内容&#xff1a;介绍 线程的 中断,等待的区别 &#x1f42f;&#x1f42f;作者简介:一名现大二的…

思科防火墙——实验练习加命令

作者简介&#xff1a;一名在校云计算网络运维学生、每天分享网络运维的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.实验练习 1.实验&#xff08;1&#xff09;配置ASA接口 2.实…

HTML网页制作代码——简约的旅游图文相册博客HTML模板(12页)HTML+CSS+JavaScript 静态HTML旅行主题网页作业

&#x1f468;‍&#x1f393;学生HTML静态网页基础水平制作&#x1f469;‍&#x1f393;&#xff0c;页面排版干净简洁。使用HTMLCSS页面布局设计,web大学生网页设计作业源码&#xff0c;这是一个不错的旅游网页制作&#xff0c;画面精明&#xff0c;排版整洁&#xff0c;内容…

大学生个人网页设计 HTML个人网页制作 web个人网站模板 简单静态HTML个人网页作品

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

[JavaEE]初始操作系统--进程

专栏简介: JavaEE从入门到进阶 题目来源: leetcode,牛客,剑指offer. 创作目标: 记录学习JavaEE学习历程 希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长. 学历代表过去,能力代表现在,学习能力代表未来! 目录 1. javaEE概述 2. 计算机发展史 3. 冯诺依曼体系 …

Allegro如何移动器件操作指导

Allegro如何移动器件操作指导 Allegro上可以任意移动器件,具体操作如下 选择Edit-move Find选择Symbols Point根据需要选择 Sym Origin是抓取器件的原点 Body center是抓取器件的中心 User Pick可以自定义抓取的原点,在移动整个模块的并且旋转的时候常用的命令 Sym Pin#设…

投稿时要求注册ORCID,这张学术界身份证到底有哪些用处?

您是否经常遇到向国际期刊投稿时需要提供ORCID账号进行登录呢&#xff1f; 又是否在我们看到喜欢的文献时&#xff0c;不免被其作者圈粉&#xff0c;忍不住要去了解这位学者的其他作品和动向时却又很难搜到准确信息&#xff1f; 对中国学者来说&#xff0c;由于投到国际期刊时…

【Matplotlib绘制图像大全】(七):Matplotlib使用xlim()和ylim()修改轴线刻度

前言 大家好,我是阿光。 本专栏整理了《Matplotlib绘制图像大全》,内包含了各种常见的绘图方法,以及Matplotlib各种内置函数的使用方法,帮助我们快速便捷的绘制出数据图像。 正在更新中~ ✨ 🚨 我的项目环境: 平台:Windows10语言环境:python3.7编译器:PyCharmMatp…

Docker-compose部署XWiki

XWiki是一个知识管理平台&#xff0c;用于知识库管理和知识管理。最有名的是Confluence系统&#xff0c;我们现在搭建的是XWiki&#xff0c;这是一个开源系统。 我们可以到官网上查找安装的方法&#xff1a; 这里&#xff0c;我们采用PostgresSQL on Tomcat的方法&#xff1a;…

15.位操作

文章目录位操作15.1二进制数、位和字节15.1.1二进制整数15.1.2有符号整数(?)15.1.3二进制浮点数1.二进制小数2.浮点数表示法15.2其他进制数15.2.1八进制15.2.2十六进制15.3C按位运算符1.二进制反码或按位取反&#xff1a;~2.按位与&#xff1a;&3.按位或&#xff1a;|4.按…

HTML+CSS网页设计期末课程大作业 【茶叶文化网站设计题材】web前端开发技术 web课程设计 网页规划与设计

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

[附源码]计算机毕业设计springboot校园代取快递系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

dreamweaver作业静态HTML网页设计——我的家乡海南旅游网站

家乡旅游景点网页作业制作 网页代码运用了DIV盒子的使用方法&#xff0c;如盒子的嵌套、浮动、margin、border、background等属性的使用&#xff0c;外部大盒子设定居中&#xff0c;内部左中右布局&#xff0c;下方横向浮动排列&#xff0c;大学学习的前端知识点和布局方式都有…

LIO-SAM源码解析(五):mapOptmization.cpp

1. 代码流程 1.1. extractSurroundingKeyFrames() 1.2. scan2MapOptimization() 这个函数主要就是进行帧到地图的匹配&#xff0c;通过点到面、点到线的距离距离最小作为优化目标。LOAM中雅阁比矩阵推导其实还是过于复杂了&#xff0c;可以使用进行误差扰动来计算雅阁比矩阵&a…

Unity事件函数的执行顺序

事件函数的执行顺序 脚本生命周期流程图 场景加载时 这些函数在场景开始时被调用&#xff08;场景中的每个对象一次&#xff09;Awake&#xff1a;此函数总是在任何 Start 函数之前以及在预制件被实例化之后调用&#xff08;如果 GameObject 在启动期间处于非活动状态&#xf…

好家伙!阿里并发核心编程宝典(2022版)一夜登顶Github热榜第三

不知道大家今年的金九银十是否有出去面试过&#xff1f;有出去面试的朋友肯定深有感受&#xff0c;像我们刚入行那会面试的加分项现在卷得已经成为了面试的基础题&#xff08;手动狗头&#xff09;。其中最典型的就属这个Java并发编程了。之前一般只有大厂才会有高并发编程相关…

[附源码]Python计算机毕业设计Django基于vuejs的爱宠用品销售app

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

three.js之模型

文章目录简介网格模型旋转平移缩放方法平移旋转属性缩放位置平移旋转复制与克隆复制方法克隆方法注意专栏目录请点击 简介 我们常见的模型有点模型&#xff0c;线模型、网格模型他们的分类如下 点模型 Points对应的材质为点材质PointsMaterial 线模型 Line 线渲染模式Line…

AIGC独角兽官宣联手,支持千亿大模型的云实例发布,“云计算春晚”比世界杯还热闹...

梦晨 发自 凹非寺量子位 | 公众号 QbitAI现在AI最火的方向是什么&#xff1f;那必须是AIGC&#xff08;AI Generated Content&#xff0c;利用人工智能技术来生成内容&#xff09;。AIGC最火的公司是谁&#xff1f;莫过于开源AI作画模型Stable Diffusion背后的StabilityAI。对于…