Linux-线程

进程 与 线程:

参考自: Linux多线程编程初探 - 峰子_仰望阳光 - 博客园 (cnblogs.com)

进程:
  典型的UNIX/Linux进程可以看成只有一个控制线程:一个进程在同一时刻只做一件事情。
有了多个控制线程后,在程序设计时可以把进程设计成在同一时刻做不止一件事,每个线程各自处理独立的任务。  

  进程是程序执行时的一个实例,是担当分配系统资源(CPU时间、内存等)的基本单位。
在面向线程设计的系统中,进程本身不是基本运行单位,而是线程的容器。
程序本身只是指令、数据及其组织形式的描述,进程才是程序(那些指令和数据)的真正运行实例。// 程序是静态概念,进程是动态概念
 

线程:
    线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。进程的所有信息对该进程的所有线程都是共享的,包括可执行的程序文本、程序的全局内存和堆内存、栈以及文件描述符。

二者联系:
 进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。
线程有自己的堆栈和局部变量,但线程没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。

二者区别:
  总的来说就是:进程有独立的地址空间,线程没有单独的地址空间(同一进程内的线程共享进程的地址空间)

使用线程理由:
 1.和进程相比,它是一种非常 "节俭"多任务操作方式。省内存,切换效率高
    2.线程间方便的通信机制 // 共享数据,方便线程间的通信 --(同一进程内的线程共享进程的地址空间)

"进程——资源分配的最小单位,线程——程序执行的最小单位"  


Linux线程开发API:

多线程开发的最基本概念主要包含三点:线程互斥锁条件  3 + 4 + 5

线程操作又分线程的创建,退出,等待 3

互斥锁则包括 4 种操作,分别是创建,销毁,加锁和解锁。

条件操作有 5 种操作:创建,销毁,触发,广播和等待。


线程:


1. 线程创建


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

// 返回:若成功返回0,否则返回错误编号


 2. 线程退出

  单个线程可以通过以下三种方式退出,在不终止整个进程的情况下停止它的控制流:

  1)线程只是从启动例程中返回,返回值是线程的退出码。

  2)线程可以被同一进程中的其他线程取消。

  3)线程调用pthread_exit:

#include <pthread.h>
int pthread_exit(void *rval_ptr);


3. 线程等待

#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);
// 返回:若成功返回0,否则返回错误编号
pthread_t pthread_self(void);
// 返回:调用线程的ID

case1:while来等待


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


// int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);

void *func1(void *arg)
{//获取当前线程ID
    printf("thread1: %ld pthread create.\n",(unsigned long)pthread_self());
    printf("thread1: param is %d\n",*((int *)arg));
}

int main()
{
    pthread_t thread1;
    int arg = 100;
    int pret;

 //创建线程1-thread1,调用函数func1,传递参数arg,NULL 创建默认属性打的线程
    pret = pthread_create(&thread1, NULL, func1, (void *)(&arg));
    if(!pret){//进程创建成功返回0
    puts("create success.");
    }
    else {//失败返回-1
        puts("create failed.");
    }
   printf("main: %ld .\n",(unsigned long)pthread_self());// 获取main函数的线程ID
    while(1); // 不加的话,主线程会没创建完线程就退出

    return 0;
}
========================================
 

case2:结合等待退出的API来调用:


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


// int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
// int pthread_exit(void *rval_ptr);
// int pthread_join(pthread_t thread, void **rval_ptr);
void *func1(void *arg)
{
    //static int pret=88; //static 保护pret退出这个函数不被销毁
     static char * p="this is run out."; // 返回字符串

    printf("thread1: %ld pthread create.\n",(unsigned long)pthread_self());
    printf("thread1: param is %d\n",*((int *)arg));
   // pthread_exit((void*)&pret);
// 线程退出 -- 里面的参数 -- 线程退出状态 -- 自己设计,可以是int 也可以是char*
 pthread_exit((void*)p); // 返回字符串
}

int main()
{
    pthread_t thread1;
   // int* pthr=NULL;
 char* pthr=NULL;  // 接收返回的字符串
    int arg = 100;
    int pret;
    pret = pthread_create(&thread1, NULL, func1, (void *)(&arg)); //arg --参数传递
    if(!pret){
    puts("create success.");
    
    }
    else {
        puts("create failed.");
    }
   printf("main: %ld .\n",(unsigned long)pthread_self());
    // 等待线程thread1退出(线程没退出phread_exit就会阻塞),第二个参数收回线程的退出

  状态,NULL--不收回
    pthread_join(thread1,(void**)&pthr); // 指针再取地址达到二级指针类型才能强制装换位二级指针
    //printf("thread quit id:%d\n",*pthr);// 查看指针拿到的退出数据
   printf("thread quit id:%s\n",pthr);// 输出进程退出返回值,字符串名就是指针
    return 0;
}
========================================
 

case3: 线程共享内存验证:


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

// int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data=0;// 共享变量
void *func1(void *arg)
{
    printf("thread1: %ld pthread create.\n", (unsigned long)pthread_self());
    printf("thread1: param is %d\n", *((int *)arg));
    while(1){
        printf("thread1:  %d\n",g_data++);
        sleep(1);
    }
  //  pthread_exit(NULL);
}
void *func2(void *arg)
{
    printf("thread2: %ld pthread create.\n", (unsigned long)pthread_self());
    printf("thread2: param is %d\n", *((int *)arg));
     while(1){
        printf("thread2:  %d\n",g_data++);
        sleep(1);
    }
   // pthread_exit(NULL);
}

int main()
{
    pthread_t thread1;
    pthread_t thread2;
    int arg = 100;
    int pret;
    pret = pthread_create(&thread1, NULL, func1, (void *)(&arg));
    if (!pret)
    {
        puts("main:create thread1 success.");
    }
    else
    {
        puts("main:create  thread1 failed.");
    }

    pret = pthread_create(&thread2, NULL, func2, (void *)(&arg));
    if (!pret)
    {
        puts("main:create thread2 success.");
    }
    else
    {
        puts("main:create thread2 failed.");
    }
     while(1){
        printf("main:  %d\n",g_data++);
        sleep(1);
    }
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    printf("main: %ld .\n", (unsigned long)pthread_self());
;

    return 0;
}
==============================

输出结果中,我们发现在func1,func2,main函数三个线程中,g_data的数据时不重样且递增的,什么我们的线程共享了进程分配到的内存


 

互斥锁API的使用:

概念:
 互斥量(mutex)从本质上来说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量上的锁

1. 创建及销毁互斥锁

#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t mutex);
// 返回:若成功返回0,否则返回错误编号
 要用默认的属性初始化互斥量,只需把attr设置为NULL。

2. 加锁及解锁

#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t mutex);
int pthread_mutex_trylock(pthread_mutex_t mutex);
int pthread_mutex_unlock(pthread_mutex_t mutex);
// 返回:若成功返回0,否则返回错误编号


 上锁后,只有在锁里面的代码执行完后才解锁,解锁前不会去调用其他进程
互斥量就是一把锁,对锁有上锁和解锁操作,这两个操作之间的代码叫共享资源,没执行完共享资源进程前,
其他进程不能调用,执行完后,其他进程可以去争抢这把锁,第一个争抢到的进程又能上锁,解锁, 这样就保证了
我们的进程是一个线程一个线程的执行,在没有执行完单曲线程之前不会去执行其他线程

case1: 互斥锁应用


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

// int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data=0;// 共享变量
pthread_mutex_t mutex;
void *func1(void *arg)
{
    int i;

    // 上锁 -- 然后后续想要再上这把锁mutex 就会被阻塞,直到这把锁被解锁,保证了上锁解锁里面的函数快能执行完,才去执行其他进程,保证进程执行的时候不受打扰
    pthread_mutex_lock(&mutex);
    for(i=0;i<3;++i)
    {
    printf("thread1: %ld pthread create.\n", (unsigned long)pthread_self());
    printf("thread1: param is %d\n", *((int *)arg));
    sleep(1);
    }

//解锁
    pthread_mutex_unlock(&mutex);
  //  pthread_exit(NULL);
}
void *func2(void *arg)
{
    pthread_mutex_lock(&mutex); // 进程1没开锁你上不了锁,阻塞在这里
    printf("thread2: %ld pthread create.\n", (unsigned long)pthread_self());
    printf("thread2: param is %d\n", *((int *)arg));
    pthread_mutex_unlock(&mutex);
   // pthread_exit(NULL);
}

int main()
{
    pthread_t thread1;
    pthread_t thread2;

    int arg = 100;
    int pret;
    //int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
    // 初始化我们的互斥🔓
    pthread_mutex_init(&mutex,NULL);

    pret = pthread_create(&thread1, NULL, func1, (void *)(&arg));
    if (!pret)
    {
        puts("main:create thread1 success.");
    }
    else
    {
        puts("main:create  thread1 failed.");
    }

    pret = pthread_create(&thread2, NULL, func2, (void *)(&arg));
    if (!pret)
    {
        puts("main:create thread2 success.");
    }
    else
    {
        puts("main:create thread2 failed.");
    }

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    printf("main: %ld .\n", (unsigned long)pthread_self());
    pthread_mutex_destroy(&mutex);//销毁互斥锁
    while (1);
   

    return 0;
}
==================================
 

case2: 互斥锁 实现对共享资源的访问:


让g_data在thread1中加到3在退出,or去执行其他进程,main函数里面没上锁就能访问
进程是线程的容器,线程可以控制进程的退出

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

// int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data=0;// 共享变量
pthread_mutex_t mutex;
void *func1(void *arg)
{

    printf("thread1: %ld pthread create.\n", (unsigned long)pthread_self());
    printf("thread1: param is %d\n", *((int *)arg));
    
    pthread_mutex_lock(&mutex);//先让下面循环里的代码执行完,再解锁
    for(;;)
    {
    printf("thread1:%d\n",g_data++);
    sleep(1);
    if(g_data==3){
      pthread_mutex_unlock(&mutex); //用完解锁
      puts("------------thread1 quit-----------------------");
      //pthread_exit(NULL);
      exit(0);
      }

    }
   
  //  pthread_exit(NULL);
}
void *func2(void *arg)
{


    
    printf("thread2: %ld pthread create.\n", (unsigned long)pthread_self());
    printf("thread2: param is %d\n", *((int *)arg));
    
    for(;;)
    {
    printf("thread2:%d\n",g_data);
    pthread_mutex_lock(&mutex); // 由于进程1没有解锁,他就会阻塞再这里上不了锁
    g_data++;
    pthread_mutex_unlock(&mutex);
    sleep(1);
    }
   
   // pthread_exit(NULL);
}

int main()
{
    pthread_t thread1;
    pthread_t thread2;
    int arg = 100;
    int pret;
    //int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
    // 初始化🔓
    pthread_mutex_init(&mutex,NULL);
    pret = pthread_create(&thread1, NULL, func1, (void *)(&arg));
    if (!pret)
    {
        puts("main:create thread1 success.");
    }
    else
    {
        puts("main:create  thread1 failed.");
    }

    pret = pthread_create(&thread2, NULL, func2, (void *)(&arg));
    if (!pret)
    {
        puts("main:create thread2 success.");
    }
    else
    {
        puts("main:create thread2 failed.");
    }
    printf("main: %ld .\n", (unsigned long)pthread_self());
    while(1){
    printf("main: g_data=%d\n",g_data);
    sleep(1);

    }
   
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    
    pthread_mutex_destroy(&mutex); //线程全部退出后销毁🔓
  

    return 0;
}

==========================


配置测试文件测试;


1).sh文件  -- shell 脚本测试

vi test.sh
//添加3个./a.out
chmod -x test.sh
// 给test可执行的权限
./test --执行三次./a.out 来测试

2).c文件使用system测试

int main()
{
  int k=3;
  while(k--){
  system("./a.out");

  }

    return 0;
}

=========================================


死锁

什么情况下回死锁:


pthread_mutex_t mutex;
pthread_mutex_t mutex2;
void *func1(void *arg)
{
   
    pthread_mutex_lock(&mutex);
    sleep(3);
    pthread_mutex_lock(&mutex2);    

     int i;
    for(i=0;i<3;++i)
    {
    printf("thread1: %ld pthread create.\n", (unsigned long)pthread_self());
    printf("thread1: param is %d\n", *((int *)arg));
    sleep(1);
    }
    pthread_mutex_unlock(&mutex);
  //  pthread_exit(NULL);
}
void *func2(void *arg)
{
    pthread_mutex_lock(&mutex2);
    sleep(3);
    pthread_mutex_lock(&mutex);    

    printf("thread2: %ld pthread create.\n", (unsigned long)pthread_self());
    printf("thread2: param is %d\n", *((int *)arg));
    pthread_mutex_unlock(&mutex);
   // pthread_exit(NULL);
}
前提2个锁:


具体:
上面这种情况就会造成死锁,进程1拿到锁1,sleep(3),期间进程2拿到锁2,sleep(3),进程1一直拿不到锁2被进程2拿走
造成了阻塞,同理,之后进程2也拿不到锁1, 这就成为了死锁


通用:
两个线程都拿到一个锁,而且都不解锁,但是都想去拿另一个锁(拿不到,被另一个线程拿走了),导致一直阻塞,造成死锁

=========================================


条件API


 1. 创建及销毁条件变量

#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t cond);
// 返回:若成功返回0,否则返回错误编号
  除非需要创建一个非默认属性的条件变量,否则pthread_cont_init函数的attr参数可以设置为NULL。

  2. 等待

#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, cond struct timespec *restrict timeout);
// 返回:若成功返回0,否则返回错误编号
  pthread_cond_wait等待条件变为真。如果在给定的时间内条件不能满足,那么会生成一个代表一个出错码的返回变量。传递给pthread_cond_wait的互斥量对条件进行保护,调用者把锁住的互斥量传给函数。函数把调用线程放到等待条件的线程列表上,然后对互斥量解锁,这两个操作都是原子操作。这样就关闭了条件检查和线程进入休眠状态等待条件改变这两个操作之间的时间通道,这样线程就不会错过条件的任何变化。pthread_cond_wait返回时,互斥量再次被锁住。

  pthread_cond_timedwait函数的工作方式与pthread_cond_wait函数类似,只是多了一个timeout。timeout指定了等待的时间,它是通过timespec结构指定。

  3. 触发

#include <pthread.h>
int pthread_cond_signal(pthread_cond_t cond);
int pthread_cond_broadcast(pthread_cond_t cond);
// 返回:若成功返回0,否则返回错误编号
  这两个函数可以用于通知线程条件已经满足。pthread_cond_signal函数将唤醒等待该条件的某个线程,而pthread_cond_broadcast函数将唤醒等待该条件的所有进程
线程控制实现线程的同步:

case:通过条件控制g_data在进程2加到3再到进程1操作一次恢复,重新让进程2操作

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

// int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data=0;// 共享变量
pthread_mutex_t mutex;
pthread_cond_t cond;// 定义条件变量

void *func1(void *arg)
{

    printf("thread1: %ld pthread create.\n", (unsigned long)pthread_self());
    printf("thread1: param is %d\n", *((int *)arg));
    
   
    for(;;)
    {
     pthread_cond_wait(&cond,&mutex);//等待条件发生 -- signal触发
 
      puts("------------thread1-----------------------");
      //pthread_exit(NULL);
   
      
       printf("thread1:%d\n",g_data++);
     
       g_data=0;
        sleep(1);

    }
   
  //  pthread_exit(NULL);
}
void *func2(void *arg)
{


    
    printf("thread2: %ld pthread create.\n", (unsigned long)pthread_self());
    printf("thread2: param is %d\n", *((int *)arg));
    
    for(;;)
    {
    printf("thread2:%d\n",g_data);
    pthread_mutex_lock(&mutex); // 上锁,保证,上锁解锁间的代码块能完整执行
    g_data++;
    if(g_data==3){
    pthread_cond_signal(&cond);//单次唤醒wait,这时候func里面的wait触发就会往下执行

    }
    pthread_mutex_unlock(&mutex);
    sleep(1);
    }
   
   // pthread_exit(NULL);
}

int main()
{
    pthread_t thread1;
    pthread_t thread2;
    int arg = 100;
    int pret;
    //int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
    pthread_cond_init(&cond,NULL); //创造条件变量
    // 初始化🔓
    pthread_mutex_init(&mutex,NULL);
    pret = pthread_create(&thread1, NULL, func1, (void *)(&arg));
    if (!pret)
    {
      //  puts("main:create thread1 success.");
    }
    else
    {
        puts("main:create  thread1 failed.");
    }

    pret = pthread_create(&thread2, NULL, func2, (void *)(&arg));
    if (!pret)
    {
       // puts("main:create thread2 success.");
    }
    else
    {
        puts("main:create thread2 failed.");
    }
    printf("main: %ld .\n", (unsigned long)pthread_self());
    while(1){
   // printf("main: g_data=%d\n",g_data);
    sleep(1);

    }
   
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    pthread_cond_destroy(&cond);// 销毁条件变量
    pthread_mutex_destroy(&mutex); //线程全部退出后销毁🔓
  

    return 0;
}


================================
 测试常用: 在指令执行后 & --后台运行。比如 ./a.out &


====================================


case2:使用宏来静态初始化:

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

// int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data=0;// 共享变量
//使用宏来静态初始化
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;

void *func1(void *arg)
{
    static int cnt=0;
    printf("thread1: %ld pthread create.\n", (unsigned long)pthread_self());
    printf("thread1: param is %d\n", *((int *)arg));
    
   
    for(;;)
    {
     pthread_cond_wait(&cond,&mutex);//等待条件发生 -- signal触发
 
      puts("------------thread1-----------------------");
      //pthread_exit(NULL);
   
      
      printf("thread1:%d\n",g_data);
       g_data=0;
        sleep(1);
        if(cnt++ ==10){
            exit(1);
        }

    }
   
  //  pthread_exit(NULL);
}
void *func2(void *arg)
{


    
    printf("thread2: %ld pthread create.\n", (unsigned long)pthread_self());
    printf("thread2: param is %d\n", *((int *)arg));
    
    for(;;)
    {
    printf("thread2:%d\n",g_data);
    pthread_mutex_lock(&mutex);
    g_data++;
    if(g_data==3){
    pthread_cond_signal(&cond);//单次唤醒wait

    }
    pthread_mutex_unlock(&mutex);
    sleep(1);
    }
   
   // pthread_exit(NULL);
}

int main()
{
    pthread_t thread1;
    pthread_t thread2;
    int arg = 100;
    int pret;
    //动态初始化  ,对应宏是静态初始化
    //int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
   // pthread_cond_init(&cond,NULL); //创造条件变量
    // 初始化🔓
   // pthread_mutex_init(&mutex,NULL);
    pret = pthread_create(&thread1, NULL, func1, (void *)(&arg));
    if (!pret)
    {
      //  puts("main:create thread1 success.");
    }
    else
    {
        puts("main:create  thread1 failed.");
    }

    pret = pthread_create(&thread2, NULL, func2, (void *)(&arg));
    if (!pret)
    {
       // puts("main:create thread2 success.");
    }
    else
    {
        puts("main:create thread2 failed.");
    }
    printf("main: %ld .\n", (unsigned long)pthread_self());
    while(1){
   // printf("main: g_data=%d\n",g_data);
    sleep(1);

    }
   
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    pthread_cond_destroy(&cond);// 销毁条件变量
    pthread_mutex_destroy(&mutex); //线程全部退出后销毁🔓
  

    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CTF-遗留的压缩包

题目描述&#xff1a;小蓝同学给你发来了他自己开发的网站链接&#xff0c;他说他故意留下了一个压缩包文件&#xff0c;里面有网站的源代码&#xff0c;他想考验一下你的网络安全技能。 下发容器&#xff0c;访问链接&#xff0c;发现都是无关内容 联想到标题说有遗留的压缩…

【JAVASE】带你了解String类的常用方法和常见操作

✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a; 再无B&#xff5e;U&#xff5e;G-CSDN博客 目标&#xff1a; 1. 认识 String 类 2. 了解 String 类的基…

运放噪声评估的来龙去脉

运放噪声评估的来龙去脉 友情提示&#xff0c;运放电路的噪声分析还是比较复杂的&#xff0c;不论是基础理论还是对应的推导过程&#xff0c;都不是特别容易。考虑到兄弟们的基础参差不齐&#xff0c;所以我还是尽量说清楚点&#xff0c;这样导致看起来就有点罗里吧嗦&#xff…

SVM向量支持机

1.通俗理解 svm&#xff1a;support vector machine目标&#xff1a;利用超平面将两类数据分割开来&#xff0c;这个超平面就是我们要设计的对象 如何设计&#xff1f;我们设计之后会有间隔&#xff0c;间隔越大分类效果就越好&#xff1b;距离决策边界最近的点我们成为支持向…

前端学习<四>JavaScript基础——20-函数简介

函数的介绍 函数&#xff1a;就是一些功能或语句的封装。在需要的时候&#xff0c;通过调用的形式&#xff0c;执行这些语句。 补充&#xff1a; 函数也是一个对象 使用typeof检查一个函数对象时&#xff0c;会返回 function 函数的作用&#xff1a; 一次定义&#xff0c;…

明明设置数字居中对齐,为什么excel的数字却不居中?

有时候在excel里&#xff0c;选中数据&#xff0c;设置对齐方式 左右居中&#xff0c;然而&#xff0c;数字却怎么都不居中&#xff0c;为什么呢&#xff1f; 1.按快捷键Ctrl1&#xff0c;打开单元格自定义格式对话框&#xff0c;看到是初始界面是在数字的会计专用&#xff0c;…

vox2vec论文速读

vox2vec: A Framework for Self-supervised Contrastive Learning of Voxel-Level Representations in Medical Images 摘要 本文介绍了 vox2vec——一种体素级表示的自监督学习 &#xff08;SSL&#xff09; 对比方法 vox2vec 表示由特征金字塔网络 &#xff08;FPN&#xf…

day9 | 栈与队列 part-1 (Go) | 232 用栈实现队列、225 用队列实现栈

今日任务 栈与队列的理论基础 (介绍:代码随想录)232 用栈实现队列(题目: . - 力扣&#xff08;LeetCode&#xff09;)225 用队列实现栈 (题目: . - 力扣&#xff08;LeetCode&#xff09; ) 栈与队列的理论基础 栈 : 先进后出 队列: 后进先出 老师给的讲解:代码随想录 …

KDTree索引(K近邻搜索,半径R内近邻搜索)——PCL

K近邻搜索&#xff08;K Nearest Neighbors&#xff09; K近邻搜索是一种基于点数量的搜索方法&#xff0c;它会找到指定点附近最接近的K个邻居点。K近邻搜索中的K值是一个参数&#xff0c;您需要指定要搜索的邻居数量。该方法适用于需要查找固定数量邻居点的情况&#xff0c;…

Rust腐蚀服务器常用参数设定详解

Rust腐蚀服务器常用参数设定详解 大家好我是艾西&#xff0c;一个做服务器租用的网络架构师上期我们分享了rust腐蚀服务器的windows系统搭建方式&#xff0c;其中启动服务器bat参数因为涉及的东西比较多所以想通过这篇文章给大家做一下详细的分享。 &#xff08;注本文中xxxx…

安装达梦(DM8)数据库(命令符安装)

一、配置DM8数据库系统环境 在CentOS7系统环境安装DM8&#xff08;达梦&#xff09;数据库前的准备。&#xff08;注意&#xff1a;安装前必须创建 dmdba 用户&#xff0c;禁止使用 root 用户安装数据库。&#xff09; 1、新建用户 运行SecureCRT工具&#xff0c;root登录168…

记一次centos合并excel,word,png,pdf为一个整体pdf的入坑爬坑过程(一直显示宋体问题)。

一、背景 原先已经简单实现了excel,word,png,pdf合成一个整体pdf的过程。并将它弄到docker容器中。 1、原先入坑的技术栈 php:7.4 (业务有涉及)php第三方包 setasign\Fpdi\Fpdi : 2.3.6 &#xff08;pdf合并&#xff09;libreoffice : 5.3.6.1ImageMagick: 6.9.10-68 2、…

VLC-Qt实现简单的视频播放器

VLC-Qt是一个结合了Qt应用程序和libVLC的免费开源库。它提供了用于媒体播放的核心类&#xff0c;以及用于快速开发媒体播放器的GUI类。由于集成了整个libVLC&#xff0c;VLC-Qt具备了libVLC的所有特性&#xff0c; 例如&#xff1a;libVLC实例和播放器、单个文件和列表播放、音…

计算机网络——CSMA/CD协议以及相关习题

目录 前言 引言 CSMA/CD协议 CSMA与CSMA/CD的区别 CSMA/CD流程 前言 本博客是博主用于复习计算机网络的博客&#xff0c;如果疏忽出现错误&#xff0c;还望各位指正。 引言 最早的以太网&#xff0c;许多计算机都连接在一根总线上工作——广播通信方式。 总线的特点想…

DVWA-xss储存型及beef下载(kali)

beef下载 apt-get update apt-get install beef-xss 登录网址是 这里的ip为虚拟机的地址 之后会让你设置密码 如果密码和用户不知道在etc/beef-xss/config.yaml可以查看 这是偷cookie的就是代码 这里是可以修改的不修改的话代码是不全的 通过beef拿到了cookies之后在网页…

【自然语言处理八-transformer实现翻译任务-一(输入)】

自然语言处理八-transformer实现翻译任务-一&#xff08;输入&#xff09; transformer架构数据处理部分模型的输入数据(图中inputs outputs outputs_probilities对应的label)以处理英中翻译数据集为例的代码 positional encoding 位置嵌入代码 鉴于transfomer的重要性&#xf…

抖音快手直播整蛊软件插件工具合集(多啦咪/梦歌)

哪一款整蛊直播软件靠谱呢&#xff1f; 相信很多粉丝宝宝们&#xff0c;在做抖音直播或者快手的都在找好用又便宜的直播整蛊插件或者软件&#xff0c;但是好用的几乎少之又少&#xff0c;今天梦歌给大家分享几个&#xff0c;目前在用的也亲测过的几个软件及插件工具给大家参考&…

记录一下MySQL8版本更改密码规则

#查看当前密码策略 show variables like validate_password%;#修改密码等级为low set global validate_password.policy LOW; #注意MySQL8版本这是点&#xff0c;不是_#修改密码长度为6 set global validate_password.length 6;#查询我的数据库中user表host和user select host,…

基于javassm的医院挂号系统

开发语言&#xff1a;Java 框架&#xff1a;ssm 技术&#xff1a;JSP JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclip…

大厂Java笔试题之判断字母大小写

/*** 题目&#xff1a;如果一个由字母组成的字符串&#xff0c;首字母是大写&#xff0c;那么就统计该字符串中大写字母的数量&#xff0c;并输出该字符串中所有的大写字母。否则&#xff0c;就输出* 该字符串不是首字母大写*/ public class Demo2 {public static void main(St…