【Linux C | 多线程编程】线程的创建、线程ID、线程属性

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
⏰发布时间⏰:2024-03-22 09:05:41

本文未经允许,不得转发!!!

目录

  • 🎄一、概述
  • 🎄二、线程的创建 pthread_create
  • 🎄三、线程ID
    • ✨2.1 线程ID相关函数
    • ✨2.2 线程ID复用
  • 🎄四、线程属性
  • 🎄五、总结


在这里插入图片描述

🎄一、概述

Linux线程库接口包括线程的创建、 退出、 取消和分离, 以及连接已经终止的线程, 互斥量, 读写锁,线程的条件等待等。

POSIX 函数函数功能描述
pthread_create创建一个线程
pthread_exit退出线程
pthread_self获取线程ID
pthread_equal检查两个线程ID是否相等
pthread_join等待线程退出
pthread_detach设置线程状态为分离状态
pthread_cancel线程的取消
pthread_cleanup_push、pthread_cleanup_pop线程退出,清理函数注册和执行

在代码里使用到上述接口函数时,使用gcc编程过程中需要加-pthread选项。

本文将介绍线程创建相关的一些知识,从pthread_create开始,然后依次介绍该函数第一个参数相关的线程ID,以及第二个函数相关的线程属性。


在这里插入图片描述

🎄二、线程的创建 pthread_create

程序开始启动的时候, 产生的进程只有一个线程, 我们称之为主线程或初始线程。 对于单线程的进程而言, 只存在主线程一个线程。 如果想在主线程之外, 再创建一个或多个线程, 就需要 pthread_create 函数。

pthread_create 函数原型:

#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
   					void *(*start_routine) (void *), void *arg);

Compile and link with -pthread.
  • 函数描述:函数 pthread_create 在调用过程中启动一个新线程。新线程通过调用 start_routine 参数指向的函数开始执行;arg参数作为 start_routine 的唯一参数传递。
  • 函数参数:
    • thread:传出参数,thread参数是 pthread_t 类型的指针,线程创建成功的话,会将分配的线程ID填入该指针指向的地址。线程的后续操作将使用该值作为线程的唯一标识。
    • attr:传入参数,第二个参数是 pthread_attr_t 类型,通过该参数可以定制线程的属性,比如可以指定新建线程栈的大小、调度策略等。 如果创建线程无特殊的要求, 该值也可以是NULL, 表示采用默认属性。
    • start_routine:传入参数,第三个参数是线程需要执行的函数。创建线程,是为了让线程执行一定的任务。线程创建成功之后,该线程就会执行start_routine函数,该函数之于线程,就如同 main 函数之于主线程。
    • arg:第四个参数是新建线程执行的 start_routine 函数的入参。新建线程如果想要正常工作,则可能需要入参,那么主线程在调用 pthread_create 的时候,就可以将入参的指针放入第四个参数以传递给新建线程。如果多个入参,可以使用结构体指针。
  • 函数返回值:如果成功,则 pthread_create 返回0;如果不成功,则 pthread_create 返回一个非0的错误码。pthread_create函数有点不同, 它会将errno作为返回值, 而不是一个负值。
    • EAGAIN:系统资源不够,或者创建线程的个数超过系统对一个进程中线程总数的限制
    • EINVAL:第二个参数attr值不合法
    • EPERM:没有合适的权限来设置调度策略或参数

通过上面的描述可以看到,pthread_create 是一个"四针"函数,也就是说它四个参数都是指针。下面是这个函数的简单使用示例:

// 02_pthread_create
// 编译:gcc 02_pthread_create.c -l pthread
#include <stdio.h>
#include <pthread.h>
void *func(void *arg)
{
	int *parg = arg;
	printf("this thread arg is %d \n", *parg);
	return NULL;
}
int main()
{
	int arg=10;
	pthread_t threadId;
	pthread_create(&threadId, NULL, func, &arg);
	while(1); // 让主线程不退出
	return 0;
}

在这里插入图片描述

🎄三、线程ID

通过 pthread_create 成功创建线程后,第一个参数会返回所创建线程的线程ID,这个线程ID不同于使用系统调用函数syscall(SYS_gettid)获得的线程ID。syscall(SYS_gettid)的ID是进程调度的范畴;而这里返回的线程ID是操作系统调度器用来标识线程的。

pthread_t到底是个什么样的数据结构呢? 因为POSIX标准并没有限制pthread_t的数据类型, 所以该类型取决于具体实现。 对于Linux目前使用的NPTL实现而言, pthread_t类型的线程ID, 本质就是一个进程地址空间上的一个地址。

typedef unsigned long int pthread_t;

pthread_t类型在Linux系统中定义在 <bits/pthreadtypes.h>头文件中,在Ubuntu可以使用命令vi /usr/include/bits/pthreadtypes.h 来查看,其完整定义如上,是unsigned long int类型的。

✨2.1 线程ID相关函数

关于线程ID,线程库NPTL提供了pthread_selfpthread_equal 两个函数来操作线程ID,它们的函数原型如下:

#include <pthread.h>
pthread_t pthread_self(void);
int pthread_equal(pthread_t t1, pthread_t t2);

Compile and link with -pthread.

pthread_self函数用于在线程指向函数中获取自身线程ID,这个函数不会调用失败,返回值就是线程ID;

pthread_equal函数用于比较两个线程ID是否相等,返回值是0的时候, 表示两个线程是同一个线程, 非零值则表示不是同一个线程。注意,比较线程ID只有在同一个进程中才有意义。

🌰举例子:

// 03_pthreadID.c
// gcc 03_pthreadID.c -l pthread
#include <stdio.h>
#include <pthread.h>
void *func1(void *arg)
{
	int *parg = arg;
	printf("this thread arg is %d, my threadID is %lx \n", *parg, (unsigned long)pthread_self());
	while(1); // 让线程不退出
}
void *func2(void *arg)
{
	pthread_t *parg = arg;
	printf("other threadId is %lx, my threadID is %lx \n", (unsigned long)*parg, (unsigned long)pthread_self());
	while(1); // 让线程不退出
}
int main()
{
	int arg=10;
	pthread_t threadId_1;
	pthread_create(&threadId_1, NULL, func1, &arg);
	pthread_t threadId_2;
	pthread_create(&threadId_2, NULL, func2, &threadId_1);
	if(0 == pthread_equal(threadId_1,threadId_1))
		printf("same threads\n");
	else
		printf("different threads\n");
	while(1); // 让主线程不退出
	return 0;
}

✨2.2 线程ID复用

在满足下列条件时, 线程ID就有可能会被复用:
1) 线程退出。
2) 线程组的其他线程对该线程执行了pthread_join, 或者线程退出前将分离状态设置为已分离。
3) 再次调用pthread_create创建线程。

看例子:

// 04_pthreadID_reuse.c
// gcc 04_pthreadID_reuse.c -l pthread
#include <stdio.h>
#include <pthread.h>
void *func(void *arg)
{
	int *parg = arg;
	printf("this thread arg is %d, my threadID is %lx \n", *parg, (unsigned long)pthread_self());
	return NULL;
}

int main()
{
	int arg=10;
	pthread_t threadId;
	pthread_create(&threadId, NULL, func, &arg);
	pthread_join(threadId,NULL); // 等待线程退出
	pthread_create(&threadId, NULL, func, &arg);

	while(1); // 让主线程不退出
	return 0;
}

运行结果,可以看到两次的线程ID是一样的:
在这里插入图片描述


在这里插入图片描述

🎄四、线程属性

pthread_create 的第二个参数是线程属性,先看看 pthread_attr_t 结构体的定义:

typedef struct
{
    int						detachstate;		//线程的分离状态
    int						schedpolicy;		//线程调度策略
    struct sched_param		schedparam;			//线程的调度参数
    int						inheritsched;		//线程的继承性
    int						scope;				//线程的作用域(竞争范围)
    size_t					guardsize;			//线程栈末尾的警戒缓冲区大小
    int						stackaddr_set;		//线程的栈设置
    void *                  stackaddr;			//线程栈的位置
    size_t					stacksize;			//线程栈的大小
}pthread_attr_t;


int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);   
功能:初始化/销毁线程的属性结构体
  • detachstate:分离状态

    • PTHREAD_CREATE_JOINABLE(默认值):线程执行完函数后不会自行释放资源;
    • PTHREAD_CANCEL_DEFERRED:线程执行完函数后,会自行终止并释放占用的资源。

    系统提供两个函数获取、设置分离状态。另外,pthread_detach函数也可以设置线程分离。

    int pthread_attr_getdetachstate(const pthread_attr_t * attr,int * detachstate);
    int pthread_attr_setdetachstate(pthread_attr_t *sttr,int detachstate);
    
  • schedpolicy:调度策略

    • SCHED_OTHER(默认值):普通策略(分时调度算法),按照优先级调度
    • SCHED_FIFO:先进先出。一个FIFO会持续执行,直到线程阻塞、结束、有更高优先级的线程就绪
    • SCHED_RR:轮转策略。给每个线程分配执行时间(时间片),当一个线程的时间片耗尽时,下一个线程执行

    其中,SCHED_OTHER 调度算法不支持为线程设置优先级,而另外两种调度算法支持。获取、设置的函数如下:

    int pthread_attr_getschedpolicy(const pthread_attr_t *, int * policy)
    int pthread_attr_setschedpolicy(pthread_attr_*, int policy)
    
  • schedparam:调度参数
    用于设置线程的优先级(默认值为 0),该属性仅当线程的 schedpolicy 属性为 SCHED_FIFO 或者 SCHED_RR 时才能发挥作用。

    int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
    int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
    struct sched_param param; // sched_param 只有一个字段 sched_priority 
    param.sched_priority = 99;
    
  • inheritsched:继承性

    • PTHREAD_INHERIT_SCHED 调度属性(schedpolicy、schedparam)继承自创建者的
    • PTHREAD_EXPLICIT_SCHED 使用attr创建的线程,从attr指定的值中获取其调度属性(schedpolicy、schedparam)。

    获取、设置函数如下:

    int pthread_attr_setinheritsched(pthread_attr_t *attr,int inheritsched);
    int pthread_attr_getinheritsched(pthread_attr_t *attr,int *inheritsched);
    
  • scope:作用域(竞争范围)

    • PTHREAD_SCOPE_SYSTEM:在系统范围内竞争资源
    • PTHREAD_SCOPE_PROCESS:在进程范围内竞争资源

    线程执行过程中,可以只和同进程内的其它线程争夺 CPU 资源,也可以和系统中所有的其它线程争夺 CPU 资源,scope 属性用于指定目标线程和哪些线程抢夺 CPU 资源。获取、设置函数如下:

    int pthread_attr_setscope(pthread_attr_t *attr, int scope);
    int pthread_attr_getscope(pthread_attr_t *attr, int *scope);
    
  • guardsize:线程栈末尾的警戒缓冲区大小
    每个线程中,栈内存的后面都紧挨着一块空闲的内存空间,我们通常称这块内存为警戒缓冲区,它的功能是:一旦我们使用的栈空间超出了额定值,警戒缓冲区可以确保线程不会因“栈溢出”立刻执行崩溃。

    int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
    int pthread_attr_getguardsize(pthread_attr_t *attr, size_t *guardsize);
    
  • stackaddr_set:线程的栈设置

    int pthread_attr_setstack(pthread_attr_t *attr,void *stackaddr, size_t stacksize);
    int pthread_attr_getstack(pthread_attr_t *attr,void **stackaddr, size_t *stacksize);
    
  • stackaddr:线程栈的位置

    int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr);
    int pthread_attr_getstackaddr(pthread_attr_t *attr, void **stackaddr);
    
  • stacksize:线程栈的大小

    int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
    int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);
    

🌰举例子:

// 05_dispaly_attr.c  这是man手册的一个展示线程属性的例子,可以仔细研究以下
// gcc 05_dispaly_attr.c -l pthread
#define _GNU_SOURCE     /* To get pthread_getattr_np() declaration */
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

#define handle_error_en(en, msg) \
	   do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

static void
display_pthread_attr(pthread_attr_t *attr, char *prefix)
{
   int s, i;
   size_t v;
   void *stkaddr;
   struct sched_param sp;

   s = pthread_attr_getdetachstate(attr, &i);
   if (s != 0)
	   handle_error_en(s, "pthread_attr_getdetachstate");
   printf("%sDetach state        = %s\n", prefix,
		   (i == PTHREAD_CREATE_DETACHED) ? "PTHREAD_CREATE_DETACHED" :
		   (i == PTHREAD_CREATE_JOINABLE) ? "PTHREAD_CREATE_JOINABLE" :
		   "???");

   s = pthread_attr_getscope(attr, &i);
   if (s != 0)
	   handle_error_en(s, "pthread_attr_getscope");
   printf("%sScope               = %s\n", prefix,
		   (i == PTHREAD_SCOPE_SYSTEM)  ? "PTHREAD_SCOPE_SYSTEM" :
		   (i == PTHREAD_SCOPE_PROCESS) ? "PTHREAD_SCOPE_PROCESS" :
		   "???");

   s = pthread_attr_getinheritsched(attr, &i);
   if (s != 0)
	   handle_error_en(s, "pthread_attr_getinheritsched");
   printf("%sInherit scheduler   = %s\n", prefix,
		   (i == PTHREAD_INHERIT_SCHED)  ? "PTHREAD_INHERIT_SCHED" :
		   (i == PTHREAD_EXPLICIT_SCHED) ? "PTHREAD_EXPLICIT_SCHED" :
		   "???");

   s = pthread_attr_getschedpolicy(attr, &i);
   if (s != 0)
	   handle_error_en(s, "pthread_attr_getschedpolicy");
   printf("%sScheduling policy   = %s\n", prefix,
		   (i == SCHED_OTHER) ? "SCHED_OTHER" :
		   (i == SCHED_FIFO)  ? "SCHED_FIFO" :
		   (i == SCHED_RR)    ? "SCHED_RR" :
		   "???");

   s = pthread_attr_getschedparam(attr, &sp);
   if (s != 0)
	   handle_error_en(s, "pthread_attr_getschedparam");
   printf("%sScheduling priority = %d\n", prefix, sp.sched_priority);

   s = pthread_attr_getguardsize(attr, &v);
   if (s != 0)
	   handle_error_en(s, "pthread_attr_getguardsize");
   printf("%sGuard size          = %ld bytes\n", prefix, v);

   s = pthread_attr_getstack(attr, &stkaddr, &v);
   if (s != 0)
	   handle_error_en(s, "pthread_attr_getstack");
   printf("%sStack address       = %p\n", prefix, stkaddr);
   printf("%sStack size          = 0x%lx bytes\n", prefix, v);
}

static void *
thread_start(void *arg)
{
   int s;
   pthread_attr_t gattr;

   /* pthread_getattr_np() is a non-standard GNU extension that
	  retrieves the attributes of the thread specified in its
	  first argument */

   s = pthread_getattr_np(pthread_self(), &gattr);
   if (s != 0)
	   handle_error_en(s, "pthread_getattr_np");

   printf("Thread attributes:\n");
   display_pthread_attr(&gattr, "\t");

   exit(EXIT_SUCCESS);         /* Terminate all threads */
}

int main(int argc, char *argv[])
{
   pthread_t thr;
   pthread_attr_t attr;
   pthread_attr_t *attrp;      /* NULL or &attr */
   int s;

   attrp = NULL;

   /* If a command-line argument was supplied, use it to set the
	  stack-size attribute and set a few other thread attributes,
	  and set attrp pointing to thread attributes object */

   if (argc > 1) {
	   int stack_size;
	   void *sp;

	   attrp = &attr;

	   s = pthread_attr_init(&attr);
	   if (s != 0)
		   handle_error_en(s, "pthread_attr_init");

	   s = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
	   if (s != 0)
		   handle_error_en(s, "pthread_attr_setdetachstate");

	   s = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
	   if (s != 0)
		   handle_error_en(s, "pthread_attr_setinheritsched");

	   stack_size = strtoul(argv[1], NULL, 0);

	   s = posix_memalign(&sp, sysconf(_SC_PAGESIZE), stack_size);
	   if (s != 0)
		   handle_error_en(s, "posix_memalign");

	   printf("posix_memalign() allocated at %p\n", sp);

	   s = pthread_attr_setstack(&attr, sp, stack_size);
	   if (s != 0)
		   handle_error_en(s, "pthread_attr_setstack");
   }

   s = pthread_create(&thr, attrp, &thread_start, NULL);
   if (s != 0)
	   handle_error_en(s, "pthread_create");

   if (attrp != NULL) {
	   s = pthread_attr_destroy(attrp);
	   if (s != 0)
		   handle_error_en(s, "pthread_attr_destroy");
   }

   pause();    /* Terminates when other thread calls exit() */
}

运行结果,打印一些默认值:
在这里插入图片描述


在这里插入图片描述

🎄五、总结

本文介绍了线程创建相关的内容,包括pthread_create函数的详细介绍和使用例子,然后依次介绍该函数第一个参数相关的线程ID知识以及第二个参数相关的线程属性知识。读完完整地了解线程的创建。

补充:
进程的地址空间:
1、Linux系统中,/proc/sys/vm/legacy_va_layout文件的值会影响进程地址空间的布局。默认值是0,表示mmap区域的基地址在栈的下面, mmap区域从高地址向低地址扩展;若值为1, 那么mmap的基地址mmap_base变小(约在128T的三分之一处),mmap区域从低地址向高地址扩展。

2、使用命令 pmap PIDcat /proc/PID/maps 可以查看进程的地址空间:
在这里插入图片描述

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

参考资料:
https://blog.csdn.net/qq_41854911/article/details/118719001
《Linux环境编程:从应用到内核》

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SSC9211_USB-CAM解决方案

一、方案描述 SSC9211是一种用于USB-CAM应用程序跟场景的高度集成的SOC产品。平台本身基于ARM层-A7双核&#xff0c;内置16位&#xff0c;64M的DDR2&#xff0c;集成了图像传感器接口、高级ISP、高性能JPEG编码器和其他丰富的外设接口。支持单&#xff0c;双 MIPI sensor方案&…

H3C--堆叠(IRF)

拓扑图 配置流程 配置SW1与SW2堆叠 一、SW1&#xff1a; shutdown 物理端口配置堆叠优先级&#xff0c;优先级高的成为主设备创建堆叠逻辑接口&#xff0c;将物理接口加入到堆叠逻辑接口中 二、SW1&#xff1a; sysname SW1 # irf member 1 priority 6 # irf-port 1/1port…

基于时空上下文(STC)的运动目标跟踪算法,Matlab实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码代做/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供…

windowsVMware虚拟机中扩展linux磁盘空间

1.虚拟磁盘扩容 VM中&#xff0c;关闭linux虚拟机&#xff0c;直接编辑虚拟机-硬盘-扩展磁盘容量 2.通过Gparted工具进行LINUX系统磁盘分区 未分区挂载前可以看到/挂载点下空间为20G&#xff1a; 通过虚拟机-快照-拍摄快照&#xff0c;操作前可拍摄快照&#xff08;便于恢复之前…

科技云报道:造完“大模型”,“具身智能”将引领AI下一个浪潮?

科技云报道原创。 资深机器人专家Eric Jang不久前曾预言&#xff1a;“ChatGPT 曾在一夜之间出现。我认为&#xff0c;有智慧的机器人技术也将如此。” 3月13日深夜&#xff0c;一段人形机器人的视频开始热传。 在视频中&#xff0c;Figure的人形机器人&#xff0c;可以完全…

基于java+springboot+vue实现的健身房管理系统(文末源码+Lw+ppt)23-523

摘 要 健身房管理的以往工作流程繁杂、多样、管理复杂与设备维护繁琐。而如今计算机已完全能够胜任健身房管理工作&#xff0c;而且更加准确、方便、快捷、高效、清晰、透明&#xff0c;它完全可以克服以上所述的不足之处。这将给查询信息和管理带来很大的方便&#xff0c;从…

从0写一个问卷调查APP的第13天-1

1.今日任务 我也只是一个大学生&#xff0c;有什么思路不对的地方给我指出来哟! 分析&#xff1a;上次我们实现了任务调查的插入。但是我们插入的问卷调查只有它的标题&#xff0c;也就是这个问卷调查是什么我们告诉数据库了&#xff0c;但是现在我们还没有给它添加任何问题&…

图片如何去除水印?试试这三款去水印工具!

在处理图片时&#xff0c;经常会遇到一个棘手的问题&#xff1a;水印。不论是想去除不美观的版权标记&#xff0c;还是希望消除图片上的杂物&#xff0c;一个好用的去水印工具都是必不可少的。今天&#xff0c;我们就为大家介绍三款功能强大、操作简便的图片去水印软件&#xf…

JavaScrpt学习笔记_一

一、Js编写位置 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> <!-- 可以将js代码编写到外部js文件中&#xff0c;然后通过script标签引入写到外部文件中可以在不同页面中…

梦百合发布“正确睡眠观”,再次呼吁“别睡硬床”

3月21日“世界睡眠日”当天,MLILY梦百合召开了主题为“别睡硬床”的品牌发布会,梦百合家居董事长倪张根发布了一场线上主题演讲,普及睡硬床可能带来的危害,呼吁国人“别睡硬床!”,并发布“100万张硬床垫改造计划”,期望消费者通过从体验一张薄垫开始,从而逐步认识到睡硬床的危害…

1.C#对接微信Native支付(接入前准备)

在申请微信支付商户和微信公众号成功后&#xff0c;我们需要根据官方文档继续进行下一步操作。 1.申请appid和申请mchid 其实只要申请了支付商户和公众号那么这两个id就已经生成了。 我们在公众号管理端的微信支付中可以看到appid 在微信支付商户管理端中可以看到mchid 2…

20240316-1-向量化搜索

向量化搜索 在高维空间内快速搜索最近邻&#xff08;Approximate Nearest Neighbor&#xff09;。召回中&#xff0c;Embedding向量的搜索。 FAISS、kd-tree、局部敏感哈希、【Amnoy、HNSW】 FAISS faiss是Facebook的AI团队开源的一套用于做聚类或者相似性搜索的软件库&…

图中的边关系和节点关系之间的转换

图中的边关系和节点关系之间的转换 边关系转为图 在relation数组中记录的是从一个节点到一个节点&#xff0c;前面的就叫做from&#xff0c;后面的就叫做to&#xff0c;因此每次添加进节点关系的数组的时候&#xff0c;from就是数组索引&#xff0c;to就是需要加入的值。也就是…

揭秘最热门AI写作软件,看看有哪些值得推荐的AI写作神器

在快节奏的现代生活中&#xff0c;我们常常面临各种压力&#xff0c;例如工作、学习等。因此&#xff0c;一款能够提高写作效率的工具变得尤为重要。那么&#xff0c;有没有什么AI写作软件是比较好用的呢&#xff1f;下面小编给大家推荐几款热门的写作软件。 一.爱制作AI写作 …

打造稳定高效的会员系统:技术架构解析与优化策略

随着互联网时代的发展和用户需求的变化&#xff0c;会员系统成为了各行各业企业实现用户粘性和增长的重要手段。一个稳定高效的会员系统架构能够帮助企业更好地管理会员数据、提供个性化服务和增加用户价值。本文将深入探讨会员系统的技术架构&#xff0c;分析其重要性和挑战&a…

Transformer的前世今生 day02(神经网络语言模型、词向量)

神经网络语言模型 使用神经网络的方法&#xff0c;去完成语言模型的两个问题&#xff0c;下图为两层感知机的神经网络语言模型&#xff1a; 假设词典V内有五个词&#xff1a;“判断”、“这个”、“词”、“的”、“词性”&#xff0c;且要输出P(w_next | “判断”、“这个”、…

Linux东方通下载及使用

把压缩包拖进去 解压文件 mkdir /usr/local/java

新品发布 | Ftrans FIE文件安全导入导出系统

关于飞驰云联 飞驰云联是中国领先的数据安全传输解决方案提供商&#xff0c;长期专注于安全可控、性能卓越的数据传输技术和解决方案&#xff0c;公司产品和方案覆盖了跨网跨区域的数据安全交换、供应链数据安全传输、数据传输过程的防泄漏、FTP的增强和国产化替代、文件传输自…

加速您的 AI 开发:NVIDIA AI Workbench 正式发布

加速您的 AI 开发&#xff1a;NVIDIA AI Workbench 正式发布 NVIDIA AI Workbench 是一款面向 AI 和 ML 开发人员的工具包&#xff0c;现已普遍提供免费下载。 它具有自动化功能&#xff0c;可以消除新手开发人员的障碍并提高专家的工作效率。 无论技能水平如何&#xff0c;开…

使用倒模耳机壳UV树脂胶液制作舞台监听耳返入耳式耳机壳有哪些优点?

使用倒模耳机壳UV树脂胶液制作舞台监听耳返入耳式耳机壳有很多优点&#xff0c;具体如下&#xff1a; 高音质表现&#xff1a;通过倒模工艺制作的耳机壳能够更好地贴合耳朵&#xff0c;减少声音散射和反射&#xff0c;提高声音的清晰度和质感。这对于舞台监听来说非常重要&…