LinuxC编程——线程的同步与互斥

news2025/2/24 16:30:37

目录

  • 一、同步的概念
  • 二、同步机制
    • 2.1 信号量
      • 2.1.1基础概念
      • 2.1.2 函数接口
      • 2.1.3 例子
    • 2.2 互斥锁
      • 2.2.1 几个概念
      • 2.2.2 函数接口
      • 2.2.3 练习
    • 2.3 条件变量
      • 2.3.1 步骤
      • 2.3.2 函数
      • 2.3.3 练习

我们知道,一个进中的所有线程共享进程的资源,所以可以通过在进程中定义全局变量来完成进程中线程间的通信,但是,当在同一内存空间运行多个线程时,要注意一个基本的问题,就是不要让线程之间互相破坏。例如,我们要实现两个线程要更新两个变量的值,一个线程要把两个变量的值都设成0,另一个线程要把两个变量的值都设成1。
如果两个线程同时要做这件事情,结果可能是,一个变量的值是0;另一个变量的值是1。这是因为正好在第1个线程把第1个变量设为0后,时间片到,CPU切换第2个线程,第2个线程将把两个变量都设成1,然后CPU再切换线程,第1个线程恢复运行,把第2个变量设成0。结果就是,一个变量的值是0,另一个变量的值是1。

因此需要同步机制来进行制约。 在System V IPC机制中提供了信号量来实现进程或线程之间的通信。此外按照POSIX标准,POSIX提供了两种类型的同步机制,它们是互斥锁(Mutex)条件变量(condition Variable)

一、同步的概念

同步是指多个 任务(线程)按照约定的顺序相互配合完成一件事。

二、同步机制

2.1 信号量

2.1.1基础概念

  • 通过信号量实现同步操作;由信号量来决定线程是继续运行还是阻塞等待
  • 信号量代表某一类资源,其值表示系统中该资源的数量,信号量值>0,表示有资源可以用,可以申请到资源,继续执行程序;信号量值<=0,表示没有资源可以用,无法申请到资源,阻塞。
  • 信号量是一个受保护的变量,只能通过三种操作来访问:初始化sem_init、P操作(申请资源)sem_wait、V操作(释放资源)sem_post

2.1.2 函数接口

  1. 初始化信号量:sem_init
    int sem_init(sem_t *sem, int pshared, unsigned int value)

    • 功能:初始化信号量
    • 参数:
      • sem:初始化的信号量对象
      • pshared:信号量共享的范围(0:线程间使用 ,非0:进程间使用)
      • value:信号量初值
    • 返回值:成功 0;失败 -1
  2. 申请资源:sem_wait
    int sem_wait(sem_t *sem)

    • 功能:申请资源 P操作
    • 参数:sem:信号量对象
    • 返回值:成功;失败 -1

    此函数执行过程,当信号量的值大于0时,表示有资源可以用,则继续执行,同时对信号量减1;当信号量的值等于0时,表示没有资源可以使用,函数阻塞。

  3. 释放资源:sem_post
    int sem_post(sem_t *sem)

    • 功能:释放资源 V操作
    • 参数:sem:信号量对象
    • 返回值:成功 0;失败 -1

    注:释放一次信号量的值加1,函数不阻塞

2.1.3 例子

  1. 测试信号量<0时,进程(线程)阻塞
    在这里插入图片描述
  2. 通过线程实现数据的交互,主线程循环从终端输入,线程函数将数据循环输出,即输入一行数据打印一行数据,当输入quit结束程序。
/*
    练习:使用信号量实现同步,即通过线程实现数据的交互,主线程循环从终端输入,
        线程函数将数据循环输出,当输入quit结束程序。
    要点:
        信号量初值的设定:初始化信号量为0,是为了让打印线程开始申请不到资源
*/
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <semaphore.h> 

char buf[32] = {0};
sem_t sem;

void *handler(void *arg) //线程函数循环输出
{
    while (1)
    {
        sem_wait(&sem); //P  申请资源
        if(strcmp(buf,"quit")==0)
        {
            pthread_exit(NULL);
        }
        printf("buf:%s\n",buf);
    }
    return NULL;
}
int main(int argc, char const *argv[])
{
    pthread_t tid; //创建线程
    if(pthread_create(&tid,NULL,handler,NULL) != 0)
    {
        perror("pthread_create err");
        return -1;
    }
    //初始化信号量为0,是为了让打印线程开始申请不到资源
    if(sem_init(&sem,0,0)<0)
    {
        perror("sem_init err\n");
        return -1;
    }
    while(1)
    {
        // scanf("%s",buf);
        fgets(buf,32,stdin);
        if(buf[strlen(buf)-1]=='\n')
            buf[strlen(buf)-1] = '\0';
        sem_post(&sem); // V  释放资源
        if(strcmp(buf,"quit")==0)
        {
            break;
        }
    }
    pthread_join(tid, NULL);
    sem_destroy(&sem);
    return 0;
}

运行结果:
在这里插入图片描述

注意:
(1)sem_t sem定义的信号量在主线程和新线程都要使用,故要定义为全局变量。
(2)信号量初值的设定:初始化信号量为0,是为了让打印线程开始申请不到资源,使得主线程获取到数据后先执行。
(3)在终端获取数据可以用scanf或者fgets,但是要注意一点就是使用fgets时,若不加处理会出现输入quit不能终止程序执行,原因是fgets会将换行作为字符捕获,这时的buf内容为quit\n\0,在使用strcmp(buf,“quit”)进行比较时,quit\n\0和quit\0并不相等。处理方法可以是将buf中quit\n\0的倒数第二个字符’\n’给替换掉,使得strcmp(buf,“quit”)可以比较成功。

  1. 通过两个线程实现数组倒置,线程1用于循环倒置,线程2用于循环打印,要满足导致一次打印一次,用信号量实现同步
/*练习:.通过两个线程实现数组倒置,线程一用于循环倒置,线程二用于循环打印。
用信号量实现同步
int a[10] = {0,1,2,3,4,5,6,7,8,9};
*/
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
sem_t sem1;

void *reverse(void *arg)
{
    int temp;
    while(1)
    {
        for (int i = 0, j = 9; i < j; i++, j--)
        {
            temp = a[i];
            a[i] = a[j];
            a[j] = temp;
        }
        sem_post(&sem1);
        sleep(1); //添加延时,保证数组倒置完成
    }
    pthread_exit(NULL);
    return NULL;
}
void *print(void *arg)
{
    while(1)
    {
        sem_wait(&sem1);
        for (int i = 0; i < 10; i++)
        {
            printf("%d ", a[i]);
        }
        printf("\n");
    }
    pthread_exit(NULL);
    return NULL;
}

int main(int argc, char const *argv[]) //主进程
{
    pthread_t tid1;
    pthread_t tid2;

    if (pthread_create(&tid1, NULL, reverse, NULL) != 0)
    {
        perror("pthread_create tid1 error");
        return -1;
    }
    if (pthread_create(&tid2, NULL, print, NULL) != 0)
    {
        perror("pthread_create tid2 error");
        return -1;
    }
    if(sem_init(&sem1,0,0)<0)
    {
        perror("sem1_init err\n");
        return -1;
    }
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    return 0;
}

注🚨:这个程序中在reverse线程函数中添加了一个1秒的延时,是为了在完成一次数组倒置信号量加一(P操作),等待print线程申请到资源并接着打印数组。若不加延时,则可能会出现reverse线程上来就执行了多次数组倒置,信号量>=2了,此时reverse线程在这次过程中还没倒置完数组,时间片就到了,CPU调度到了print线程,就会打印出没有倒置完的数组,如下的运行结果👇
在这里插入图片描述

还可以不加延时,那要再加一个信号量,用两个信号量来实现这个题的同步,如下代码👇

/*练习:.通过两个线程实现数组倒置,线程一用于循环倒置,线程二用于循环打印。
用信号量实现同步
*/
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
sem_t sem1;
/*****新加的********/
sem_t sem2;
/******************/

void *reverse(void *arg)
{
    int temp;
    while(1)
    {
        /*****新加的********/        
        sem_wait(&sem2);
        /******************/        
        for (int i = 0, j = 9; i < j; i++, j--)
        {
            temp = a[i];
            a[i] = a[j];
            a[j] = temp;
        }
        sem_post(&sem1);
        // sleep(1);
    }
    pthread_exit(NULL);
    return NULL;
}
void *print(void *arg)
{
    while(1)
    {
        sem_wait(&sem1);
        for (int i = 0; i < 10; i++)
        {
            printf("%d ", a[i]);
        }
        printf("\n");
        /*****新加的********/ 
        sem_post(&sem2);
        /******************/ 
    }
    pthread_exit(NULL);
    return NULL;
}

int main(int argc, char const *argv[]) //主进程
{
    pthread_t tid1;
    pthread_t tid2;

    if (pthread_create(&tid1, NULL, reverse, NULL) != 0)
    {
        perror("pthread_create tid1 error");
        return -1;
    }
    if (pthread_create(&tid2, NULL, print, NULL) != 0)
    {
        perror("pthread_create tid2 error");
        return -1;
    }
    if(sem_init(&sem1,0,0)<0)
    {
        perror("sem1_init err\n");
        return -1;
    }
    /*****新加的********/
    if(sem_init(&sem1,0,1)<0)
    {
        perror("sem2_init err\n");
        return -1;
    }
    /*******************/
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    return 0;
}

在这里插入图片描述

2.2 互斥锁

2.2.1 几个概念

  • 临界资源:一次仅允许一个进程所使用的资源
  • 临界区:指的是一个访问共享资源的程序片段
  • 互斥:多个线程在访问临界资源时,同一时间只能一个线程访问
  • 互斥锁:通过互斥锁可以实现互斥机制,主要用来保护临界资源,每个临界资源都由一个互斥锁来保护,线程必须先获得互斥锁才能访问临界资源,访问完资源后释放该锁。如果无法获得锁,线程会阻塞直到获得锁为止。

2.2.2 函数接口

  1. 初始化互斥锁:pthread_mutex_init
    int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr)

    • 功能:初始化互斥锁
    • 参数
      • mutex:互斥锁
      • attr: 互斥锁属性 // NULL表示缺省属性
    • 返回值:成功 0;失败 -1
  2. 申请互斥锁:pthread_mutex_lock
    int pthread_mutex_lock(pthread_mutex_t *mutex)

    • 功能:申请互斥锁
    • 参数:mutex:互斥锁
    • 返回值:成功 0;失败 -1

    注:和pthread_mutex_trylock区别:pthread_mutex_lock是阻塞的;pthread_mutex_trylock不阻塞,如果申请不到锁会立刻返回

  3. 释放互斥锁:pthread_mutex_unlock
    int pthread_mutex_unlock(pthread_mutex_t *mutex)

    • 功能:释放互斥锁
    • 参数:mutex:互斥锁
    • 返回值:成功 0;失败 -1
  4. 销毁互斥锁:pthread_mutex_destroy
    int pthread_mutex_destroy(pthread_mutex_t *mutex)

    • 功能:销毁互斥锁
    • 参数:mutex:互斥锁

2.2.3 练习

通过两个线程实现数组倒置,线程1用于循环倒置,线程2用于循环打印,要满足导致一次打印一次。用互斥锁实现

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

int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
pthread_mutex_t lock;

void *reverse(void *arg)
{
    int temp;
    while (1)
    {
        pthread_mutex_lock(&lock);
        for (int i = 0; i < 10/2; i++)
        {
            temp = a[i];
            a[i] = a[9-i];
            a[9-i] = temp;
        }
        pthread_mutex_unlock(&lock);
    }
}
void *print(void *arg)
{
    while (1)
    {
        pthread_mutex_lock(&lock);
        for (int i = 0; i < 10; i++)
        {
            printf("%d ", a[i]);
        }
        printf("\n");
        pthread_mutex_unlock(&lock);
        sleep(1);
    }
}

int main(int argc, char const *argv[])
{
    pthread_t tid1, tid2;
    if (pthread_create(&tid1, NULL, reverse, NULL) != 0)
    {
        perror("pthread_create tid1 error");
        return -1;
    }
    if (pthread_create(&tid2, NULL, print, NULL) != 0)
    {
        perror("pthread_create tid2 error");
        return -1;
    }

    if (pthread_mutex_init(&lock, NULL))
    {
        perror("mutex err");
    }

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    pthread_mutex_destroy(&lock);

    return 0;
}

在这里插入图片描述

注📢:这个程序可以实现循环倒置与打印,因为通过互斥锁保护了临界资源,实现了互斥,不会出现还未倒置完就会打印出来的情况,但是不能实现倒置一次打印一次(下面的条件变量可以实现)。因为两个线程并不是交替执行,而是谁抢到时间片谁执行。比如有可能倒置线程先抢到时间片先执行,然后打印线程抢到时间片执行两次,等等其他无次序交替执行。

2.3 条件变量

2.3.1 步骤

  1. pthread_cond_init:初始化
  2. pthread_cond_wait:阻塞等待条件产生,若没有条件产生会阻塞并且解锁,当有条件产生,再次上锁。所以在使用时先上锁再调用pthread_cond_wait
  3. pthread_cond_signal:产生条件,不阻塞
  4. pthread_cond_destory:销毁条件变量

2.3.2 函数

  1. 初始化条件变量:pthread_cond_init
    int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);

    • 功能:初始化条件变量
    • 参数:
      • cond:是一个指向结构pthread_cond_t 的指针
      • restrict attr:是一个指向结构pthread_condattr_t的指针,一般设为NULL
    • 返回值:成功:0 ;失败:非0
  2. 等待信号的产生:pthread_cond_wait
    int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);

    • 功能:等待信号的产生
    • 参数
      • restrict cond:要等待的条件
      • restrict mutex:对应的锁
    • 返回值:成功:0,失败:不为0

    注📢🚨⭐🎯:当没有条件产生时函数会阻塞,同时会将锁解开;如果等待到条件产生,函数会结束阻塞同时进行上锁

  3. 产生条件:pthread_cond_signal
    int pthread_cond_signal(pthread_cond_t *cond);

    • 功能:给条件变量发送信号
    • 参数:cond:条件变量值
    • 返回值:成功:0,失败:非0

    注:必须等待pthread_cond_wait函数先执行,再产生条件

  4. 销毁条件:pthread_cond_destroy
    int pthread_cond_destroy(pthread_cond_t *cond);

    • 功能:将条件变量销毁
    • 参数:cond:条件变量值
    • 返回值:成功:0, 失败:非0

2.3.3 练习

通过两个线程实现数组倒置,线程1用于循环倒置,线程2用于循环打印,实现终端间隔1秒交替循环输出,要先输出倒置的数组。用 互斥锁+条件变量 实现此同步

/*练习:.通过两个线程实现数组倒置,线程一用于循环倒置,线程二用于循环打印。
用互斥锁 + 条件变量实现同步
int a[10] = {0,1,2,3,4,5,6,7,8,9};
*/
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
pthread_mutex_t lock;
pthread_cond_t cond;

void *reverse(void *arg)
{
    int temp;
    while (1)
    {
        sleep(1); //保证print先抢到锁,让其阻塞等待信号
        pthread_mutex_lock(&lock);
        for (int i = 0, j = 9; i < j; i++, j--)
        {
            temp = a[i];
            a[i] = a[j];
            a[j] = temp;
        }
        pthread_cond_signal(&cond);  //产生条件
        pthread_mutex_unlock(&lock); //解锁
    }
    pthread_exit(NULL);
    return NULL;
}
void *print(void *arg)
{
    while (1)
    {
        pthread_mutex_lock(&lock);
        // 阻塞等待条件产生,若没条件,则解锁,条件到来解除阻塞上锁
        pthread_cond_wait(&cond, &lock);
        for (int i = 0; i < 10; i++)
        {
            printf("%d ", a[i]);
        }
        printf("\n");
        pthread_mutex_unlock(&lock);
    }
    pthread_exit(NULL);
    return NULL;
}
int main(int argc, char const *argv[]) //主进程
{
    pthread_t tid1;
    pthread_t tid2;
    if (pthread_mutex_init(&lock, NULL)) //初始化互斥锁
    {
        perror("mutex_init err");
        return -1;
    }
    if (pthread_cond_init(&cond, NULL)) //初始化条件变量
    {
        perror("cond_init err");
        return -1;
    }
    // 创建线程
    if (pthread_create(&tid1, NULL, reverse, NULL) != 0)
    {
        perror("pthread_create tid1 error");
        return -1;
    }
    if (pthread_create(&tid2, NULL, print, NULL) != 0)
    {
        perror("pthread_create tid2 error");
        return -1;
    }
    // 阻塞回收线程
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    pthread_mutex_destroy(&lock);
    pthread_cond_destroy(&cond);
    return 0;
}

在这里插入图片描述
注📢:reverse线程函数里的sleep(1)放在加锁的上面,是为了保证print线程先抢到锁,让其在pthread_cond_wait处阻塞等待条件信号(pthread_cond_signal)产生,然后再reverse线程得到执行,实现数组的倒置,保证第一次的输出结果是倒置后的数据。

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

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

相关文章

【概念篇】文件概述

✅作者简介&#xff1a;大家好&#xff0c;我是小杨 &#x1f4c3;个人主页&#xff1a;「小杨」的csdn博客 &#x1f433;希望大家多多支持&#x1f970;一起进步呀&#xff01; 文件概述 1&#xff0c;文件的概念 狭义上的文件是计算机系统中用于存储和组织数据的一种数据存…

大华智慧园区综合管理平台文件上传漏洞复现(HW0day)

0x01 产品简介 “大华智慧园区综合管理平台”是一款综合管理平台&#xff0c;具备园区运营、资源调配和智能服务等功能。平台意在协助优化园区资源分配&#xff0c;满足多元化的管理需求&#xff0c;同时通过提供智能服务&#xff0c;增强使用体验。 0x02 漏洞概述 大华智慧园…

PowerShell 使用SqlScriptDOM对T-SQL做规则校验

对于数据项目来说&#xff0c;编写Sql是一项基本任务同时也是数量最多的代码。为了统一项目代码规范同时降低Code Review的成本&#xff0c;因此需要通过自动化的方式来进行规则校验。由于本人所在的项目以SQL Server数据库为基础&#xff0c;于是本人决定通过使用SqlScriptDom…

静态库和动态库制作

文章目录 前言一、静态库和动态库介绍1、静态库2、动态库 二、静态库的制作及使用1、准备好源码2、编译源码生成 .o 文件3、制作静态库4、使用静态库 三、动态库的制作及使用1、生成位置无关的 .o 文件2、制作动态库3、使用动态库4、指定动态库路径并使其生效 四、对比1、静态库…

初步制作做一个AI智能工具网站,持续更新

文章目录 介绍AI对话AI绘画AI音视频AI图片处理AI小工具体验 介绍 网页有五大部分&#xff1a;AI对话、AI绘画、AI音视频、AI 图片处理、AI小工具。 AI对话 AI对话是指人工智能技术在模拟人类对话交流方面的应用。通过使用自然语言处理和机器学习算法&#xff0c;AI对话系统可…

Flink CDC系列之:基于 Flink CDC 构建 MySQL 和 Postgres 的 Streaming ETL

Flink CDC系列之&#xff1a;基于 Flink CDC 构建 MySQL 和 Postgres 的 Streaming ETL 一、技术路线二、MySQL数据库建表三、PostgreSQL数据库建表四、在 Flink SQL CLI 中使用 Flink DDL 创建表五、关联订单数据并且将其写入 Elasticsearch 中六、Kibana查看商品和物流信息的…

基于Java+SpringBoot+Vue的书籍学习平台设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

Chrome

Chrome 简介下载 简介 Chrome 是由 Google 开发的一款流行的网络浏览器。它以其快速的性能、强大的功能和用户友好的界面而闻名&#xff0c;并且在全球范围内被广泛使用。Chrome 支持多种操作系统&#xff0c;包括 Windows、macOS、Linux 和移动平台。 Chrome官网: https://ww…

深度剖析堆栈指针

为什么打印root的值与&root->value的值是一样的呢 测试结果&#xff1a; *号一个变量到底取出来的是什么&#xff1f; 以前我写过一句话&#xff0c;就是说&#xff0c;如果看到一个*变量&#xff0c;那就是直逼这个变量所保存的内存地址&#xff0c;然后取出里面保存的…

Java负载均衡算法实现与原理分析(轮询、随机、哈希、加权、最小连接)

文章目录 一、负载均衡算法概述二、轮询&#xff08;RoundRobin&#xff09;算法1、概述2、Java实现轮询算法3、优缺点 三、随机&#xff08;Random&#xff09;算法1、概述2、Java实现随机算法 四、源地址哈希&#xff08;Hash&#xff09;算法1、概述2、Java实现地址哈希算法…

在Java中对XML的简单应用

XML 数据传输格式1 XML 概述1.1 什么是 XML1.2 XML 与 HTML 的主要差异1.3 XML 不是对 HTML 的替代 2 XML 语法2.1 基本语法2.2 快速入门2.3 组成部分2.3.1 文档声明格式属性 2.3.2 指令&#xff08;了解&#xff09;&#xff1a;结合CSS2.3.3 元素2.3.4 属性**XML 元素 vs. 属…

c++ 学习系列 -- 智能指针

一 为什么引入智能指针&#xff1f;解决了什么问题&#xff1f; C 程序设计中使用堆内存是非常频繁的操作&#xff0c;堆内存的申请和释放都由程序员自己管理。但使用普通指针&#xff0c;容易造成内存泄露&#xff08;忘记释放&#xff09;、二次释放、程序发生异常时内存泄…

Springboot整合RabbitMq,详细步骤

Springboot整合RabbitMq&#xff0c;详细步骤 1 添加springboot-starter依赖2 添加连接配置3 在启动类上添加开启注解EnableRabbit4 创建RabbitMq的配置类&#xff0c;用于创建交换机&#xff0c;队列&#xff0c;绑定关系等基础信息。5 生产者推送消息6 消费者接收消息7 生产者…

闭环控制方法及其应用:优缺点、场景和未来发展

闭环控制是一种基本的控制方法&#xff0c;它通过对系统输出与期望值之间的误差进行反馈&#xff0c;从而调整系统输入&#xff0c;使系统输出更加接近期望值。闭环控制的主要目标是提高系统的稳定性、精确性和鲁棒性。在实际应用中&#xff0c;闭环控制有多种方法&#xff0c;…

开源代码分享(13)—整合本地电力市场与级联批发市场的投标策略(附matlab代码)

1.引言 1.1摘要 本地电力市场是在分配层面促进可再生能源的效率和使用的一种有前景的理念。然而&#xff0c;作为一个新概念&#xff0c;如何设计和将这些本地市场整合到现有市场结构中&#xff0c;并从中获得最大利润仍然不清楚。在本文中&#xff0c;我们提出了一个本地市场…

linux添加磁盘

一、linux虚拟机添加一块新的硬盘 四步&#xff1a; &#xff08;1&#xff09; &#xff08;2&#xff09;为硬盘进行分区 &#xff08;3&#xff09;初始化硬盘分区 &#xff08;4&#xff09;挂载 在虚拟机上添加一块硬盘 (1)、 虚拟机添加一块新的硬盘作为数据盘 (2) ls…

Idea Live Template 功能总结

文章目录 Java自带的template属性模板psf——public static finalpsfi——public static final intpsfi——public static final StringSt——String 方法模板psvm——main方法sout——打印语句iter——for迭代循环fori——for循环 代码块模板if-e —— if elseelse-if 自定义自…

中国首款量子计算机操作系统本源司南 PilotOS正式上线

中国安徽省量子计算工程研究中心近日宣布&#xff0c;中国国产量子计算机操作系统本源司南 PilotOS 客户端正式上线。 如果把量子芯片比喻成人的“心脏”&#xff0c;那么量子计算机操作系统就相当于人的“大脑”&#xff0c;量子计算应用软件则是人的“四肢”。 据安徽省量子…

Linux 终端命令之文件浏览(1) cat

Linux 文件浏览命令 cat, more, less, head, tail&#xff0c;此五个文件浏览类的命令皆为外部命令。 hannHannYang:~$ which cat /usr/bin/cat hannHannYang:~$ which more /usr/bin/more hannHannYang:~$ which less /usr/bin/less hannHannYang:~$ which head /usr/bin/he…

论文总结《Towards Evaluating the Robustness of Neural Networks(CW)》

原文链接 C&W 这篇论文更像是在讲一个优化问题&#xff0c;后面讲述如何针对生成对抗样本的不可解问题近似为一个可解的问题&#xff0c;很有启发。本文后面将总结论文各个部分的内容。 Motivation 文章提出了一个通用的设计生成对抗样本的方法&#xff0c;根据该论文提…