IO进程线程day6(2023.8.3)

news2024/12/26 11:17:41

一、Xmind整理:

进程与线程关系: 

二、课上练习:

练习1:pthread_create

功能:创建一个线程

原型:

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

参数:

pthread_t *thread:存储创建后的线程的tid号;
pthread_attr_t *attr:线程属性; 填NULL,代表默认属性。或者用pthread_attr_init(3)初始化线程属性后 
                      传参进入:分离属性。
void *(*start_routine) (void *):回调函数,函数指针,该函数指针指向线程执行体。
该指针可以指向返回值是void*类型,参数列表是void*类型的函数,例如:
void* handler(void* arg){                                                                                    
                        }
void *arg:传递给回调函数的参数;

返回值:

成功,返回0;
失败,返回错误编号,即非0,没说更新errno,所以不能用perror打印;

注意: 

1.从main函数进来的线程称之为主线程,pthread_create创建的线程称之为分支线程或者子线程。

2.一般来说主线程会先运行,但是还是要依照时间片轮询机制

3.主线程退出后(main函数结束),会导致进程结束,依附于该进程内的线程均会被强制退出。

4.其他线程退出后,会不会影响到主线程。

创建一个分支线程:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
#include <pthread.h>
//线程的执行体
void* CallBack(void* arg)
{
    while(1)
    {
        printf("this is other fun:__%d__\n",__LINE__);
        sleep(1);
    }
    return NULL;
}
int main(int argc, const char *argv[])
{
    //创建一个分支线程
    pthread_t tid;
    if(pthread_create(&tid,NULL,CallBack,NULL) != 0)
    {
        fprintf(stderr,"pthread_create failed:__%d__\n",__LINE__);
        return -1;
    }
    while(1)
    {                                                               
        printf("this is main fun:__%d__\n",__LINE__);
        sleep(1);
    }

    return 0;
}

练习2:线程的传参 

问题1:定义一个全局变量int a=10,主线程和分支线程能否访问到,访问到的是否是同一份资源。

答案:均能访问到,且是同一份资源

问题2:在主线程定一个局部变量int b=10,分支线程能否访问到。

答案:不能,局部变量作用域在定义他的函数内部

问题3:在分支线程定义一个局部变量int c=10,主线程能否访问到。

答案:不能,局部变量作用域在定义他的函数内部

问题4:若访问不到,用什么方式可以让对方线程访问到。

i. 主线程传参给分支线程 :

 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <head.h>
 #include <pthread.h>
 //线程的执行体
 void* CallBack(void* arg)   //void* arg = (void*)&c
 {
     //void* arg使用解引用的时候,需要先强转
     //如果直接*arg,会导致操作系统不知道该访问几个字节
     while(1)
     {
         printf("this is other func c=%d\t %p__%d__\n",*(int*)arg,arg,__LINE__);
         sleep(1);
     }
     return NULL;
 }
 int main(int argc, const char *argv[])
 {                                                                               
     int c = 10;
     //创建一个分支线程
     pthread_t tid;
     if(pthread_create(&tid,NULL,CallBack,(void*)&c) != 0)
     {
         fprintf(stderr,"pthread_create failed:__%d__\n",__LINE__);
         return -1;
     }
     while(1)
     {
         printf("this is other func c=%d\t %p__%d__\n",c,&c,__LINE__);
         sleep(1);
     }
     return 0;
 }
 

ii. 分支线程传参给主线程 :

 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <head.h>
 #include <pthread.h>
 //线程的执行体
 void* CallBack(void* arg)   //void* arg = (void*)&tmp_c
 {
     //void* arg使用解引用的时候,需要先强转
     //如果直接*arg,会导致操作系统不知道该访问几个字节
     int c = 10;
     *(int*)arg = c;        //*(int*)arg访问的就是tmp_c
     while(1)
     {
         printf("this is other func c=%d\t %p__%d__\n",c,&c,__LINE__);
         sleep(1);
     }
     return NULL;
 }
 int main(int argc, const char *argv[])
 {
     int tmp_c = -1;
     //创建一个分支线程
     pthread_t tid;
     if(pthread_create(&tid,NULL,CallBack,(void*)&tmp_c) != 0)
     {
         fprintf(stderr,"pthread_create failed:__%d__\n",__LINE__);
         return -1;
     }
     while(1)                                                                    
     {
         printf("this is other func c=%d\t %p__%d__\n",tmp_c,&tmp_c,__LINE__);
         sleep(1);
     }
     return 0;
 }

 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <head.h>
 #include <pthread.h>
 //线程的执行体
 void* CallBack(void* arg)   //void* arg = (void*)&pc
 {
     //void* arg使用解引用的时候,需要先强转
     //如果直接*arg,会导致操作系统不知道该访问几个字节
     int c = 10;
 
     //由于arg存储了pc的地址,所以arg可以访问pc的内存空间
     //由于pc空间的类型为int*,所以*arg访问出来的类型也得是int*
     //所以arg类型应该是int**类型
     *(int**)arg = &c;        //*(int**)arg访问的是pc的内存空间
     while(1)
     {
         printf("this is other func c=%d\t %p__%d__\n",c,&c,__LINE__);
         sleep(1);
     }
     return NULL;
 }                                                                                 
 int main(int argc, const char *argv[])
 {
     int* pc = NULL;
     //创建一个分支线程
     pthread_t tid;
     if(pthread_create(&tid,NULL,CallBack,(void*)&pc) != 0)
     {
         fprintf(stderr,"pthread_create failed:__%d__\n",__LINE__);
         return -1;
     }
     while(1)
     {
         if(pc!=NULL)
         {
             printf("this is other func c=%d\t %p__%d__\n",*pc,pc,__LINE__);
             sleep(1);
         }
     }
     return 0;
 }
 

练习3:pthread_exit

功能:退出分支线程,并传递线程退出状态值

原型:

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

参数:

 void *retval:指定要传递给主线程的状态值,如果不想传递,填NULL;
 传递的线程退出状态值被pthread_join函数接收;

当分支线程退出后,会残留一部分资源,例如线程的tid号,线程调度块等等,若不回收会出现类似僵尸线程的状态;

需要使用pthread_join等函数回收;

练习4:pthread_join

功能:阻塞函数,阻塞等待指定的分支线程退出,并接收分支线程退出状态值,

           同时回收分支线程的资源

原型:

#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);

参数:

pthread_t thread:指定要等待哪个线程,填对应的tid号;
void **retval:若retval不为空,则该函数会将线程退出状态值(void* retval)拷贝到该二级指针指向的一级指针的内存空间中,
若不想接收填NULL;
If retval is not NULL, then pthread_join() copies  the  exit
status of the target thread  into  the   location pointed  to  by  retval. 

返回值:

成功,返回0;
失败,返回错误编号,即非0,没说更新errno,所以不能用perror打印;

小练1:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
#include <pthread.h>
//线程的执行体
void* CallBack(void* arg)   //void* arg = NULL
{
    int i = 0;
    while(i<3)
    {
        printf("this is other func:__%d__\n",__LINE__);
        sleep(1);
        i++;
    }
    pthread_exit(NULL);     //专门用于退出线程
    printf("退出分支线程\n");
    return NULL;
}

int main(int argc, const char *argv[])
{
    //创建一个分支线程
    pthread_t tid;
    if(pthread_create(&tid,NULL,CallBack,NULL) != 0)
    {
        fprintf(stderr,"pthread_create failed:__%d__\n",__LINE__);
        return -1;
    }                                                                     
    printf("this is main func  __%d__\n",__LINE__);
    pthread_join(tid,NULL);  //阻塞等待tid分支线程退出
    printf("主线线程准备退出\n");
    return 0;
}

小练2: 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
#include <pthread.h>
//线程的执行体
void* CallBack(void* arg)   //void* arg = NULL
{
    int i=0;
    while(i<3)
    {
        printf("this is other fun:__%d__\n",__LINE__);
        sleep(1);
        i++;
    }

    printf("分支线程准备退出\n");
    static int a =10;    //延长生命周期,防止线程退出后被释放
    printf("&a = %p\n",&a);
    pthread_exit(&a);    //void* retval = &a;
                                                                       
}

int main(int argc, const char *argv[])
{
    //创建一个分支线程
    pthread_t tid;
    if(pthread_create(&tid,NULL,CallBack,NULL) != 0)
    {
        fprintf(stderr,"pthread_create failed:__%d__\n",__LINE__);
        return -1;
    }
    printf("this is main func  __%d__\n",__LINE__);
    //线程退出状态值会被拷贝到&pret指向的一级指针(pret)中
    //即 pret=&a;
    void* pret=NULL;
    pthread_join(tid,&pret);       //阻塞等待tid分支线程退出
    printf("pret = %d %p\n",*(int*)pret,pret);
    printf("主线线程准备退出\n");
    return 0;
}

小练3:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
#include <pthread.h>
//线程的执行体
void* CallBack(void* arg)   //void* arg = NULL
{
    int i=0;
    while(i<3)
    {
        printf("this is other fun:__%d__\n",__LINE__);
        sleep(1);
        i++;
    }

    printf("分支线程准备退出\n");
    char* ptr = (char*)malloc(12);                                  
    strcpy(ptr,"hello world");
    pthread_exit(ptr);
}

int main(int argc, const char *argv[])
{
    //创建一个分支线程
    pthread_t tid;
    if(pthread_create(&tid,NULL,CallBack,NULL) != 0)
    {
        fprintf(stderr,"pthread_create failed:__%d__\n",__LINE__);
        return -1;
    }
    printf("this is main func  __%d__\n",__LINE__);

    //线程退出状态值会被拷贝到&ptr指向的一级指针(pret)中
    //即pret = ptr;
    void* pret = NULL;
    pthread_join(tid,&pret);
    printf("%s\n",(char*)pret);
    free(pret);
    printf("主线线程准备退出\n");
    return 0;
}

练习5:创建两个线程:其中一个线程拷贝前半部分,另一个线程拷贝后半部分。

 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <head.h>
 #include <pthread.h>
 
 //拷贝前半部分
 void* CallBack1(void* arg)
 {
     //以读的方式打开源文件
     int fd_r = open("./1.png",O_RDONLY);
     if(fd_r < 0)
     {
         ERR_MSG("open");
         return NULL;
     }
     //以写的方式打开目标文件
     int fd_w = open("./2.png",O_WRONLY);
     if(fd_w < 0)
     {
         ERR_MSG("open");
         return NULL;
     }
     off_t size = lseek(fd_r,0,SEEK_END);
 
     //修改文件偏移量到文件开头位置
     lseek(fd_r,0,SEEK_SET);
     lseek(fd_w,0,SEEK_SET);
     char c=0;
     for(int i=0;i<size/2;i++)
     {
         read(fd_r,&c,1);
         write(fd_w,&c,1);
     }
     printf("前半部分拷贝完毕\n");
     //关闭文件
     close(fd_r);
     close(fd_w);
     pthread_exit(NULL);
 }
 //拷贝后半部分
 void* CallBack2(void* arg)     //void* arg=&fileinfo
 {
     //以读的方式打开源文件
     int fd_r = open("./1.png",O_RDONLY);
     if(fd_r < 0)
     {
         ERR_MSG("open");
         return NULL;
     }
     //以写的方式打开目标文件
     int fd_w = open("./2.png",O_WRONLY,0664);
     if(fd_w < 0)
     {
         ERR_MSG("open");
         return NULL;
     }
     off_t size = lseek(fd_r,0,SEEK_END);
 
     //修改文件偏移量到文件开头位置
     lseek(fd_r,size/2,SEEK_SET);
     lseek(fd_w,size/2,SEEK_SET);
     char c=0;
     for(int i=size/2;i<size;i++)
     {
         read(fd_r,&c,1);
         write(fd_w,&c,1);
     }
     printf("后半部分拷贝完毕\n");
     //关闭文件
     close(fd_r);
     close(fd_w);
     pthread_exit(NULL);
 }
 
 int main(int argc, const char *argv[])
 {
     //两个线程在拷贝前,确保文件存在,且是清空状态
     int fd_w = open("./2.png",O_WRONLY|O_CREAT|O_TRUNC,0664);
     if(fd_w < 0)                                                                          
     {
         ERR_MSG("open");
         return -1;
     }
     close(fd_w);
 
     //创建一个线程
     pthread_t tid1,tid2;
     if(pthread_create(&tid1,NULL,CallBack1,NULL) != 0)
     {
         fprintf(stderr,"pthread_create failed:__%d__\n",__LINE__);
         return -1;
     }
     if(pthread_create(&tid2,NULL,CallBack2,NULL) != 0)
     {
         fprintf(stderr,"pthread_create failed:__%d__\n",__LINE__);
         return -1;
     }
 
     //阻塞等待分支线程退出
     pthread_join(tid2,NULL);
     pthread_join(tid1,NULL);
 
 
     return 0;
 }

练习6:pthread_detach

功能:分离线程,线程退出后资源由系统自动回收

原型:

#include <pthread.h>
int pthread_detach(pthread_t thread);

参数:

 pthread_t thread:指定要分离哪个线程;

返回值:

成功,返回0;
失败,返回错误编号,即非0,没说更新errno,所以不能用perror打印;

注意:当使用pthread_detach分离tid线程后,pthread_join函数就无法再回收tid线程的资源了,且pthread_join函数不阻塞!

练习7:pthread_cancel

功能:请求指定线程退出; 请求成功,对方线程不一定退出

原型:

#include <pthread.h>
int pthread_cancel(pthread_t thread);

参数:

 pthread_t thread:指定要请求哪个线程退出;

返回值:

成功,返回0;
失败,返回错误编号,即非0,没说更新errno,所以不能用perror打印;
1.pthread_cancel会给目标线程打上一个退出标识,cpu切换到目标线程后,运行到退出标识,才会让目标线程退出。

2.但是while for 等循环结构,以及算数运算等等位置,无法打上退出标识。所以当目标线程只有上述结构的时候,无法用pthread_cancel退出线程

3.printf ,sleep等等函数结构可以打上退出标识

4.请求成功,不代表目标线程一定会退出

练习8:要求定义一个全局变量 char buf[] = "1234567",创建两个线程,不考虑退出条件。

①A线程循环打印buf字符串

②B线程循环倒置buf字符串,即buf中本来存储1234567,倒置后buf中存储7654321. 不打印!!

③倒置不允许使用辅助数组。

④要求A线程打印出来的结果只能为 1234567 或者 7654321 不允许出现7634521 7234567

⑤不允许使用sleep函数

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

char buf[] = "1234567";
int flag = 0;

void* callBack1(void* arg)
{
    while(1)
    {
        if(0 == flag)
        {
            printf("%s\n", buf);
            flag = 1;
        }
    }
    pthread_exit(NULL);
}

void* callBack2(void* arg)
{
    char tmp = 0;
    while(1)                                                                               
    {
        if(1 == flag)
        {
            for(int i=0; i<strlen(buf)/2; i++)
            {
                tmp = buf[i];
                buf[i] = buf[strlen(buf)-1-i];
                buf[strlen(buf)-1-i] = tmp;
            }
            flag = 0;
        }
    }

    pthread_exit(NULL);
}


int main(int argc, const char *argv[])
{
    pthread_t tid1, tid2;
    if(pthread_create(&tid1, NULL, callBack1, NULL) != 0)
    {
        fprintf(stderr, "pthread_create failed __%d__\n", __LINE__);
        return -1;
    }
    pthread_detach(tid1);   //分离线程1

    if(pthread_create(&tid2, NULL, callBack2, NULL) != 0)
    {
        fprintf(stderr, "pthread_create failed __%d__\n", __LINE__);
        return -1;
    }

    pthread_join(tid2, NULL);   //阻塞等待线程2退出

    return 0;
}

练习9:pthread_mutex_init

功能:创建一个互斥锁

原型:

#include <pthread.h>
pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;
int pthread_mutex_init(pthread_mutex_t *mutex, const
pthread_mutexattr_t *mutexattr);

参数:

pthread_mutex_t *mutex:存储申请后的互斥锁;
const pthread_mutexattr_t *mutexattr:互斥锁属性,设置互斥锁适用于进程间还是线程间的同步互斥锁。
                                      填NULL,默认属性,用于线程

返回值:

永远成功,返回0;

练习10:pthread_mutex_lock

功能:对互斥锁进行上锁,若有其他线程占用互斥锁,该函数会阻塞

原型:

#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);

参数:

pthread_mutex_t *mutex;

返回值:

成功,返回0;
失败,返回非0,没有说更新errno,所以不要用perror打印错误。

练习11:pthread_mutex_unlock

功能:解开互斥锁

原型:

#include <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex);

参数:

pthread_mutex_t *mutex;

返回值:

成功,返回0;
失败,返回非0,没有说更新errno,所以不要用perror打印错误。

练习12:pthread_mutex_destroy

功能:销毁互斥锁

原型:

#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);

参数:

pthread_mutex_t *mutex;

返回值:

成功,返回0;
失败,返回非0,没有说更新errno,所以不要用perror打印错误。

小练: 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
#include <pthread.h>
//临界资源
char buf[]="1234567";

//互斥锁
pthread_mutex_t mutex;

void* CallBack1(void* arg)
{
    while(1)
    {
        /**********临界区*********/
        //上锁
        pthread_mutex_lock(&mutex);
        printf("%s\n",buf);
        //解锁
        pthread_mutex_unlock(&mutex);
        /**********临界区*********/
    }
    pthread_exit(NULL);
}
void* CallBack2(void* arg)
{
    char tmp=0;
    while(1)
    {
        /**********临界区*********/
        //上锁                                                              
        pthread_mutex_lock(&mutex);
        for(int i=0;i<strlen(buf)/2;i++)
        {
            tmp=buf[i];
            buf[i]=buf[strlen(buf)-1-i];
            buf[strlen(buf)-1-i]=tmp;
        }
        //解锁
        pthread_mutex_unlock(&mutex);
        /**********临界区*********/
    }
    pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
    //申请一个互斥锁
    pthread_mutex_init(&mutex,NULL);

    pthread_t tid1,tid2;
    if(pthread_create(&tid1,NULL,CallBack1,NULL) != 0)
    {
        fprintf(stderr,"pthread_create failed:__%d__\n",__LINE__);
        return -1;
    }
    pthread_detach(tid1);  //分离线程1
        if(pthread_create(&tid2,NULL,CallBack2,NULL) != 0)
        {
            fprintf(stderr,"pthread_create failed:__%d__\n",__LINE__);
            return -1;
        }

    pthread_join(tid2,NULL);        //阻塞等待线程2退出

    //销毁互斥锁
    pthread_mutex_destroy(&mutex);

    return 0;
}

三、课后作业:

1.创建两个线程:其中一个线程拷贝前半部分,另一个线程拷贝后半部分。

   只允许开一份资源,且用互斥锁方式实现。 提示:找临界区--->找临界资源。

#include <stdio.h>
#include <pthread.h>
#include <head.h>
 
//创建互斥锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 
struct Msg
{
	int fd_r;
	int fd_w;
	off_t size;
};
void *callBack1(void *arg)
{
	int fd_r = ((struct Msg *)arg)->fd_r;
	int fd_w = ((struct Msg *)arg)->fd_w;
	off_t size = ((struct Msg *)arg)->size;
	char c;
 
    //上锁
	pthread_mutex_lock(&mutex);
	lseek(fd_r,0,SEEK_SET);
	lseek(fd_w,0,SEEK_SET);
	for(int i = 0;i<size/2;i++)
	{
		read(fd_r,&c,1);
		write(fd_w,&c,1);
	}
    //解锁
	pthread_mutex_unlock(&mutex);
 
	pthread_exit(NULL);
}
void *callBack2(void *arg)
{
	int fd_r = ((struct Msg *)arg)->fd_r;
	int fd_w = ((struct Msg *)arg)->fd_w;
	off_t size = ((struct Msg *)arg)->size;
	char c;
	
    //上锁
	pthread_mutex_lock(&mutex);
	lseek(fd_r,size/2,SEEK_SET);
	lseek(fd_w,size/2,SEEK_SET);
	for(int i=size/2;i<size;i++)
	{
		read(fd_r,&c,1);
		write(fd_w,&c,1);
	}
    //解锁
	pthread_mutex_unlock(&mutex);
 
	pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
	int fd_r = open("./1.png",O_RDONLY);
	if(fd_r < 0)
	{
		perror("open");
		return -1;
	}
	int fd_w = open("./2.png",O_WRONLY|O_CREAT|O_TRUNC,0664);
	if(fd_w < 0)
	{
		perror("open");
		return -1;
	}
	off_t size = lseek(fd_r,0,SEEK_END);
	struct Msg Copy;
	Copy.fd_r = fd_r;
	Copy.fd_w = fd_w;
	Copy.size = size;
 
	pthread_t tid1,tid2;
	if(pthread_create(&tid1,NULL,callBack1,&Copy) != 0)
	{
		fprintf(stderr,"pthread_create failed __%d__",__LINE__);
		return -1;
	}
	if(pthread_create(&tid2,NULL,callBack2,&Copy) != 0)
	{
		fprintf(stderr,"pthread_create failed __%d__",__LINE__);
		return -1;
	}
 
	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
 
	pthread_mutex_destroy(&mutex);
	close(fd_r);
	close(fd_w);
	return 0;
}

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

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

相关文章

【新版系统架构补充】-七层模型

网络功能和分类 计算网络的功能 &#xff1a;数据通信、资源共享、管理集中化、实现分布式处理、负载均衡 网络性能指标&#xff1a;速率、带宽&#xff08;频带宽度或传送线路速率&#xff09;、吞吐量、时延、往返时间、利用率 网络非性能指标&#xff1a;费用、质量、标准化…

三、基本流程控制结构

3.1结构化程序设计 基本控制结构&#xff1a; 顺序结构选择结构循环结构 C语句&#xff1a; 说明语句控制语句函数调用语句表达式语句空语句复合语句 3.2选择结构语句 if语句&#xff1a; &#xff08;1&#xff09;单选条件语句 if(表达式) 语句 if(x>y) cout<&l…

Tomcat的介绍和安装配置、eclipse中动态web项目的创建和运行、使用IDEA创建web项目并运行

一、Tomcat的介绍和安装配置 安装tomcat&#xff1a; 环境变量的配置&#xff1a; 配置之后重启cmd&#xff0c;执行startup命令&#xff0c;启动tomcat 在localhost:8080&#xff0c;能进入tomcat主界面&#xff0c;说明配置成功 二、eclipse中动态web项目的创建和运行 tomca…

基于回溯算法实现八皇后问题

八皇后问题是一个经典的计算机科学问题&#xff0c;它的目标是将8个皇后放置在一个大小为88的棋盘上&#xff0c;使得每个皇后都不会攻击到其他的皇后。皇后可以攻击同一行、同一列和同一对角线上的棋子。 一、八皇后问题介绍 八皇后问题最早由国际西洋棋大师马克斯贝瑟尔在18…

王道《操作系统》学习(二)—— 进程管理(二)

2.1 处理机调度的概念、层次 2.1.1 调度的基本概念 2.1.2 调度的三个层次 &#xff08;1&#xff09;高级调度&#xff08;作业调度&#xff09; &#xff08;2&#xff09;中级调度&#xff08;内存调度&#xff09; 补充知识&#xff1a;进程的挂起状态和七状态模型 &#x…

Three.js室内场景

Three.js实现三维可视化室内场景 1.效果 2.安装 要安装three 的 npm 模块,请在你的项目文件夹里打开终端窗口,并运行: npm install three 或 yarn add three包将会被下载并安装。然后你就可以将它导入你的代码了: import * as THREE from three引入性能监视器: impor…

MySQL日志——错误日志、二进制日志

错误日志二进制日志查询日志慢查询日志 1.错误日志 查看日志位置&#xff1a; show variables like %log_error%查看错误日志&#xff1a; tail -f /var/log/mysql.log2.二进制日志 show variables like %log_bin%;cd /var/lib/mysql ll2.1 日志格式 查看日志格式指令&…

第9章 CSS-DOM

三位一体的网页 游览器由结构层&#xff0c;表现层&#xff0c;行为层组成 结构层 网页的结构层&#xff08;structural layer&#xff09;由HTML或XHTML之类的标记语言负责创建。 表现层 表示层&#xff08;presentation layer&#xff09;由CSS负责完成。CSS描述页面内容…

腾讯云COS+PicGO+截图工具+Obsidian+Typora+蚁小二:打造丝滑稳定的Markdown写作和分发环境

背景 很久很久以前&#xff0c;我写过一篇《有道云笔记EverythingTyporaGitHub图床PicGojsDelivr加速截图工具——创造丝滑免费的Markdown写作环境》&#xff08;https://blog.csdn.net/qq_43721542/article/details/9685957&#xff09;&#xff0c;当时的目的是打造一个云同…

中国艺术孙溟㠭篆刻作品《活着》

人人为生活挣扎着&#xff0c;做着不想做的事&#xff0c;说着不想说的话&#xff0c;为生活低头弯腰委屈求全人生苦多甜少&#xff0c;何时了&#xff01;何时了&#xff01;甜来人生到头了…… 孙溟㠭篆刻作品《活着》 孙溟㠭篆刻作品《活着》 孙溟㠭篆刻作品《活着》 文/九钵

美团基础架构面经总结汇总

美团基础架构的面经。 问的全是基础,一个编程语言的问都没有。 问题记录 MySQL-MVCC InooDB是通过 MVCC 实现可重复读的隔离级别的,MVCC 就是多版本并发控制,它其实记录了历史版本的数据,解决了读写并发冲突问题。有一个版本编码,然后它进入了各种操作下的数据状态,能…

2023华数杯数学建模A题思路 - 隔热材料的结构优化控制研究

# 1 赛题 A 题 隔热材料的结构优化控制研究 新型隔热材料 A 具有优良的隔热特性&#xff0c;在航天、军工、石化、建筑、交通等 高科技领域中有着广泛的应用。 目前&#xff0c;由单根隔热材料 A 纤维编织成的织物&#xff0c;其热导率可以直接测出&#xff1b;但是 单根隔热…

JDK19 - 虚拟线程详解

JDK19 - 虚拟线程详解 前言一. Continuation 和 虚拟线程1.1 Continuation 案例1.2 Continuation 内的重要成员1.3 run() 执行/恢复执行1.4 yield() 暂停执行1.5 测试和小总结 二. VirtualThread 解读2.1 VirtualThread 内的重要成员和构造2.2 VirtualThread 的首次执行2.3 结束…

Kubernetes高可用集群二进制部署(二)ETCD集群部署

Kubernetes概述 使用kubeadm快速部署一个k8s集群 Kubernetes高可用集群二进制部署&#xff08;一&#xff09;主机准备和负载均衡器安装 Kubernetes高可用集群二进制部署&#xff08;二&#xff09;ETCD集群部署 Kubernetes高可用集群二进制部署&#xff08;三&#xff09;部署…

problem(2):快速访问Github

访问GitHub慢&#xff0c;这是所有程序员都遇到的问题&#xff0c;今天给大家推荐一款软件&#xff0c;让我们浏览GitHub和浏览gitee一样快&#xff0c;这个开源软件就是FastGithub。 github加速神器&#xff0c;解决github打不开、用户头像无法加载、releases无法上传下载、g…

【MATLAB第64期】基于MATLAB的无目标函数SOBOL等全局敏感性分析法模型合集(SOBOL,PAWN,GSA,GSUA,GSAT等) 【更新中】

【MATLAB第64期】基于MATLAB的无目标函数SOBOL等全局敏感性分析法模型合集(SOBOL,PAWN,GSA,GSUA,GSAT等) 【更新中】 引言 在前面几期&#xff0c;介绍了局部敏感性分析法&#xff0c;本期来介绍全局敏感性分析模型&#xff0c;因还在摸索中&#xff0c;所以更新较慢&#xf…

复现原型链污染

目录 原型链污染是什么 例1 复现 例2 复现 原型链污染是什么 第一章中说到&#xff0c;foo.__proto__指向的是Foo类的prototype。那么&#xff0c;如果我们修改了foo.__proto__中的值&#xff0c;是不是就可以修改Foo类呢&#xff1f; 做个简单的实验&#xff1a; // foo是一个…

【Linux】揭秘:提升dd命令效率的秘密武器!

红帽RHCE试听课程&#xff1a;如何快速实现对服务器密码爆破&#xff1f;https://mp.weixin.qq.com/s/JUpf8G86jvnNwvKLUfWcLQ 红帽RHCE试听课程&#xff1a;linux系统下&#xff0c;用这个命令可以提高60%的工作效率https://mp.weixin.qq.com/s/pZVjMI1PLJzrA8hoPzkgMA 大家好…

LNMP及论坛搭建(第一个访问,单节点)

LNMP&#xff1a;目前成熟的一个企业网站的应用模式之一&#xff0c;指的是一套协同工作的系统和相关软件 能够提供静态页面服务&#xff0c;也可以提供动态web服务&#xff0c;LNMP是缩写 L&#xff1a;指的是Linux操作系统。 N&#xff1a;指的是nginx&#xff0c;nginx提…

MS17-010永恒之蓝漏洞复现

一&#xff0c;认识永恒之蓝 1&#xff0c;简介 永恒之蓝&#xff0c;代号MS17-010。爆发于2017年&#xff0c;其通过控制用户主机&#xff0c;利用SMB协议的漏洞来获取系统的最高权限&#xff0c;进而可以窃取信息&#xff0c;偷窥隐私&#xff0c;甚至使系统瘫痪。曾爆发覆盖…