Linux 多进程多线程编程

2023-05-16

一 创建进程

1 进程号

进程号的类型是pid_t(typedef unsigned int pid_t)。

获得进程和父进程ID的API如下:

#include <sys/types.h>
#include <unistd.h>
pid_t getpid();//获得进程ID
pid_t getppid();//获得父进程ID

2 进程复制

进程复制可以通过fork()函数以为进城为蓝本复制一个进程,其ID号和父进程不同,fork()执行一次返回两次。

父进程中返回子进程ID,子进程中返回0;创建进程失败返回-1。

#include <sys/types.h>
#include <unistd.h>
pid_t fork();

3 system()方式

system()函数调用shell的外部命令在当前进程中开始另一个进程。

调用成功会返回进程状态值,shell不能执行返回127,失败返回-1

#include <stdlib.h>
int system(const char *command);

4 进程执行exec()函数系列

exec()族函数会用更新进程代替原有的进程,新进程PID和原进程相同。

在当系统的可执行路径中根据指定的文件名找到合适的可执行文件名,并用来取代调用进程的内容,即在原来的进程内部运行一个可执行文件。

程序执行成功不返回,失败返回-1

#include <unistd.h>
int execl(const char *path, const char *arg, ...);
int execle(const char *path, const char *arg, ... , char * const envp[]);
int execv(const char *path, char *const argv[]);
int execve(const char *filename, char *const argv[], char *const envp[]);
int execvp(const char *file, char * const argv[]);
int execlp(const char *file, const char *arg, ...);  

其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。

exec调用举例如下:

char *const ps_argv[] ={"ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL};  
char *const ps_envp[] ={"PATH=/bin:/usr/bin", "TERM=console", NULL};  
execl("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);  
execv("/bin/ps", ps_argv);  
execle("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL, ps_envp);  
execve("/bin/ps", ps_argv, ps_envp);  
execlp("ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);  
execvp("ps", ps_argv);  

注意exec函数族形参展开时的前两个参数

  • 第一个参数是带路径的执行码(execlp、execvp函数第一个参数是无路径的,系统会根据PATH自动查找然后合成带路径的执行码)。
  • 第二个是不带路径的执行码,执行码可以是二进制执行码和Shell脚本。

二 进程间通信

1 进程通过半双工管道通信

输入的数组是一个文件描述符的数组,用于保存管道返回的两个文件描述符(输入的时候直接定义数组,不需要赋初值)。

#include <unistd.h>
int pipe(int filedes[2]);

读写数据分别为read()和write()函数。关闭读写端口用close()函数。

int write(int *fd, char *str, int len);
//返回写入的字符数
//参数为:指向写端口的指针,写入的字符串指针,写入的字符串长度
int read(int *fd, char *buffer, int len);
//返回读到的字符数
//参数为:指向读端口的指针,要读入的缓冲区间指针,读到的字符串长度
void close(int *fd);
//参数为端口指针

2 命名管道

和普通管道不同之处:

  • 在文件系统中命名管道是以设备特殊文件的形式存在的。
  • 不同的进程可以通过命名管道共享数据。

mkfifo()会依参数pathname建立特殊的FIFO文件,该文件必须不存在,而参数mode为该文件的权限

若成功则返回0,否则返回-1,错误原因存于errno中。

创建函数如下:

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode)

3 消息队列

消息队列是内核地址空间中的内部链表,通过Linux内核在各个进程之间传送内容,每个消息队列可以用IPC标识符位移地进行确认。不同的消息队列之间相互独立,每个消息队列中的消息,又构成一个独立的链表。

消息缓冲区常用结构为msgbuf结构(可自定义,如设置mtext长度,结构体总长度不能大于8192字节),位于

4 信号量

信号量是计数器,用来控制对多个进程共享的资源锁进行的访问,某个进程在对特定资源进行操作时,信号量可以防止另一个进程去访问它。

新建信号量函数semget()

创建一个新的信号量或获取一个已经存在的信号量的键值。

key为整型值,用户可以自己设定。有两种情况:键值是IPC_PRIVATE,该值通常为0,意思就是创建一个仅能被进程进程给我的信号量;键值不是IPC_PRIVATE,我们可以指定键值,例如1234;也可以一个ftok()函数来取得一个唯一的键值。

nsems 表示初始化信号量的个数;

semflg:信号量的创建方式或权限,有IPC_CREAT和IPC_EXCL,IPC_CREAT如果信号量不存在,则创建一个信号量,否则获取。IPC_EXCL只有信号量不存在的时候,新的信号量才建立,否则就产生错误。

成功返回信号量的标识码ID。失败返回-1;

#include <sys/types.h>
#include <sys/ipc.h>
#include<sys/sem.h>
int semget(key_t key, int nsems, int semflg);

信号量操作函数semop()

信号量的P、V操作是通过向已经建立好的信号量(使用senget()函数),发送semop()命令来完成的。用户通过semop()改变信号量的值。也就是使用资源还是释放资源使用权。

semid:信号量的标识码。也就是semget()的返回值。

sops指向要在信号量集合上执行操作的数组。

struct   sembuf{
    unsigned short sem_num;//要处理的信号量的编号,第一个信号的编号为0
    short sem_op;
    short sem_flg;
};

sem_op : 如果其值为正数,该值会加到现有的信号内含值中。通常用于释放所控资源的使用权;如果sem_op的值为负数,而其绝对值又大于信号的现值,操作将会阻塞,直到信号值大于或等于sem_op的绝对值。通常用于获取资源的使用权;如果sem_op的值为0,则操作将暂时阻塞,直到信号的值变为0。

sem_flg可取的值如下:

  • IPC_NOWAIT:对信号的操作不能满足时,semop()不会阻塞,并立即返回,同时设定错误信息。
  • IPC_UNDO:程序结束时(不论正常或不正常),保证信号值会被重设为semop()调用前的值。这样做的目的在于避免程序在异常情况下结束时未将锁定的资源解锁,造成该资源永远锁定。

成功返回0,失败返回-1。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, unsigned int nsops);

信号量控制函数semctl()

在这个函数中我们可以删除信号量或初始化信号量。

semid:信号量的标志码(ID),也就是semget()函数的返回值。

semnum:操作信号在信号集中的编号。从0开始。是信号量集合的一个索引值。

cmd:命令,表示要进行的操作。取值如下:

  • IPC_STAT读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。
  • IPC_SET设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
  • IPC_RMID将信号量集从内存中删除。
  • GETALL用于读取信号量集中的所有信号量的值。
  • GETNCNT返回正在等待资源的进程数目。
  • GETPID返回最后一个执行semop操作的进程的PID。
  • GETVAL返回信号量集中的一个单个的信号量的值。
  • GETZCNT返回这在等待完全空闲的资源的进程数目。
  • SETALL设置信号量集中的所有的信号量的值。
  • SETVAL设置信号量集中的一个单独的信号量的值。

第4个参数是可选的;semunion:是union semun的实例。

  • val:当使用SETVAL命令时用到这个成员,它用于指定把信号量设置为什么值
  • buf:IPC_STAT/IPC_SET使用,他代表内核中所使用的内部信号量数据结构的一个复制。
  • array:GETALL/SETALL时使用,指向整数值的一个数组,在设置或者获取集合中所有信号量的值的过程中,将会用到此数组。

成功返回0,失败返回-1。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ...);

5 共享内存

共享内存是在多个进程之间共享内存区域的一种进程间的通信方式,它实在多个进程之间对内存段进行映射的方式实现共享内存的。

创建共享内存函数shmget()

得到一个现有的共享内存标识符或创建一个共享内存对象并返回共享内存标识符。

key:共享内存关键字的值,将与内核中现有的共享内存段的关键字值进行比较。0(IPC_PRIVATE):会建立新共享内存对象,大于0的32位整数:视参数shmflg来确定操作。通常要求此值来源于ftok()返回的IPC键值

size:大于0的整数:新建的共享内存大小,以字节为单位,0:只获取共享内存时指定为0

shmflg:0:取共享内存标识符,若不存在则函数会报错;IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符;IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相等的共享内存,则新建一个消息队列;如果存在这样的共享内存则报错。

PS:上述shmflg参数为模式标志参数,使用时需要与IPC对象存取权限(如0600)进行 | 运算来确定信号量集的存取权限。

返回的错误代码有:

  • EINVAL:参数size小于SHMMIN或大于SHMMAX
  • EEXIST:预建立key所指的共享内存,但已经存在
  • EIDRM:参数key所指的共享内存已经删除
  • ENOSPC:超过了系统允许建立的共享内存的最大值(SHMALL)
  • ENOENT:参数key所指的共享内存不存在,而参数shmflg未设IPC_CREAT位
  • EACCES:没有权限
  • ENOMEM:核心内存不足

成功:返回共享内存的标识符,出错:-1,错误原因存于error中

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg)

映射共享内存地址函数shmat()

连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问。

msqid:共享内存标识符

shmaddr:指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置

shmaddr:SHM_RDONLY:为只读模式,其他为读写模式

成功返回附加好的共享内存地址;出错返回-1,错误原因存于error中。

错误代码如下:

  • EACCES:无权限以指定方式连接共享内存
  • EINVAL:无效的参数shmid或shmaddr
  • ENOMEM:核心内存不足

fork()后子进程继承已连接的共享内存地址。exec后该子进程与已连接的共享内存地址自动脱离(detach)。进程结束后,已连接的共享内存地址会自动脱离(detach)

#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg)

删除内存共享函数shmdt()

与shmat()函数相反,是用来断开与共享内存附加点的地址,禁止本进程访问此片共享内存。

shmaddr:连接的共享内存的起始地址。

成功返回0;出错返回-1,错误原因存于error中:EINVAL:无效的参数shmaddr

本函数调用并不删除所指定的共享内存区,而只是将先前用shmat函数连接(attach)好的共享内存脱离(detach)目前的进程。在成功完成断开连接操作后,shmid_ds结构的shm_nattch成员的值将减去1,如果这个值减到0,内核将真正删除该内存段。

#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr)

共享内存控制函数shmctl()

完成对共享内存的控制,向共享内存的句柄(共享内存标识符)发送命令来完成某种功能。

shmid:共享内存标识符

cmd取值如下:

  • IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中
  • IPC_SET:改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内
  • IPC_RMID:删除这片共享内存

buf:共享内存管理结构体。为命令的参数部分

成功返回0,出错返回-1,错误原因存于error中。

错误代码为:

  • EACCESS:参数cmd为IPC_STAT,确无权限读取该共享内存
  • EFAULT:参数buf指向无效的内存地址
  • EIDRM:标识符为msqid的共享内存已被删除
  • EINVAL:无效的参数cmd或shmid
  • EPERM:参数cmd为IPC_SET或IPC_RMID,却无足够的权限执行

函数原型为:

#include <sys/types.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf)

6 信号

signal()用于截取系统的信号,对此信号挂接用户自己的处理函数:

返回一个函数指针。第一个参数signum是一个整型数,第二个参数是函数指针

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

挂接了信号处理函数后,可以等待系统信号的到来,用户也可以自己构造信号发送到目标进程中。此类函数有raise()和kill()。

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);//向进程号为pid的进程发送信号,信号值为sig。当pid为0时。向当前系统的所有进程发送信号sig
int raise(int sig);//在当前进程中自举一个信号sig

三 线程

1 线程创建函数

可以通过pthread_create()函数创建新线程。

tidp:新创建的线程ID会被设置成tidp指向的内存单元。用于标识一个线程。是pthread_t类型的变量

typedef unsigned long int pthread_t;

attr:用于定制各种不能的线程属性,默认为NULL

start_rtn:新创建的线程从start_rtn函数的地址开始运行,该函数只有一个void类型的指针参数即arg,如果start_rtn需要多个参数,可以将参数放入一个结构中,然后将结构的地址作为arg传入

arg:线程函数运行时传入的参数。

若成功,返回0;否则,返回错误编码,常见的错误为EAGAIN(线程数量达到上限)和EINVAL(线程属性非法)

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

2 线程结束函数

pthread_join()

pthread_join()函数会一直阻塞调用线程,直到指定的线程tid终止。当pthread_join()返回之后,应用程序可回收。

tid:需要等待的线程,指定的线程必须位于当前的进程中,而且不得是分离线程。

status:线程tid所执行的回调函数start_rtn()的返回值(start_rtn()返回值地址需要保证有效),其中status可以为null。

调用成功完成后,pthrea_join()返回0。其他任何返回值都表示出现了错误。

int pthread_join(pthread_t tid, void **status);

pthread_exit()

使用函数pthread_exit退出线程,这是线程的主动行为;由于一个进程中的多个线程是共享数据段的,因此通常在线程退出之后,退出线程所占用的资源并不会随着线程的终止而得到释放,但是可以用pthread_join()函数来同步并释放资源。

retval:pthread_exit()调用线程的返回值,可由其他函数如pthread_join()来检索获取。

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

3 线程的属性

线程的属性结构为pthread_attr_t,在头文件

4 线程间的互斥

多线程编程中,可以用互斥锁(也称互斥量)可以用来保护关键代码段,以确保其独占式的访问,这有点像二进制信号量。互斥锁相关函数主要有以下5个:

#include <pthread.h>  
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);//互斥初始化
int pthread_mutex_destroy(pthread_mutex_t *mutex);//锁定互斥  
int pthread_mutex_lock(pthread_mutex_t *mutex);//互斥预锁定
int pthread_mutex_trylock(pthread_mutex_t *mutex);//解锁互斥
int pthread_mutex_unlock(pthread_mutex_t *mutex);//销毁互斥

互斥锁类型为pthread_mutex_t。

5 线程中使用信号量

信号量是一个非负的整数计数器,用来实现对公共资源的控制。

PV原子操作

P操作:

  • 如果有可用的资源(信号量值>0),则此操作所在的进程占用一个资源(此时信号量值减1,进入临界区代码);
  • 如果没有可用的资源(信号量值=0),则此操作所在的进程被阻塞直到系统将资源分配给该进程(进入等待队列,一直等到资源轮到该进程)。

V操作:

  • 如果在该信号量的等待队列中有进程在等待资源,则唤醒一个阻塞进程;如果没有进程等待它,则释放一个资源(即信号量值加1)。

信号量主要函数如下:

#include <semaphore.h>
sem_t sem        //定义信号量                            
sem_init(sem_t *sem, int pshared, unsigned int value)       //初始化信号量 
//sem:指向信号量结构的一个指针
//pshared:信号量的共享类型,不为0时信号来那个可以在进程间共享,否则只能在当前进程的线程间共享
//value:设置信号量初始化的时候信号量的值             
sem_wait(sem_t *sem)       //获取信号量,信号量的数值-1,如果信号量为0,组线程阻塞到信号量值大于0为止,信号量为0时不再减少
/* 访问共享资源代码 */
sem_post(sem_t *sem)       //释放一个信号量,及信号量的数值+1    
sem_destroy(sem_t *sem)    //如果不再使用信号量,则销毁信号量
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux 多进程多线程编程 的相关文章

  • alibaba pc safe service无法删除,一直在后台运行怎么办?

    对付流氓软件 xff0c 应当使用师夷长技以制夷的办法 xff0c 下载一个腾讯电脑管家 xff0c 然后下载里面的文件粉碎机 xff0c 在任务管理器找到对应的alibaba pc safe service服务 xff0c 点击进入具体的
  • APP流量变现之穿山甲广告平台接入

    1 首先百度搜索 穿山甲广告投放 xff0c 第一个出现的链接就是开发者官网 xff0c 截图如下 xff1a 2 进入之后点击注册 xff0c 然后登陆 xff08 这一步穿山甲超级简单 xff0c 如果不着急提现收益的话 xff0c 可
  • spss统计分析基础教程(上)--自学

    64 TOC 目录 xff09 第一章 四种窗口 数据窗口 输出窗口 语法窗口 脚本窗口 菜单 1 文件 xff1a 新建 打开 保存 另存为 将文件标记为只读 xff1a 如果之后保存文件 xff0c 则只能重命名并另存 重新命名数据集
  • OpenWrt 内的阿里云盘 WebDAV 做磁盘使用

    最近在玩OpenwWrt的时候 xff0c 在刷的固件里看到预装的阿里云盘 WebDAV xff0c 加上最近刚刚开始用阿里云 xff0c 不限速 xff0c 非常快 xff0c 通过这个服务 xff0c 可以直接把阿里云的文件架挂载在本地
  • VS2022中使用Copilot

    Copilot可以自动帮你写代码 1 打开vs2022 点击扩展 xff0c 在里面搜索copilot安装 2 安装完成后 xff0c 左下角有个小图标就是copilot 3 点击登录 会弹框 点击确定后 xff0c 跳转到网站 xff0c
  • CSS/SCSS/LESS和自适应布局/响应式布局详解

    在开发前端的时候 xff0c 界面布局尤为重要 xff0c 要布局的非常合理 xff0c 好看 xff0c css是必不可少的 xff0c 然后是各种布局 xff0c 使用这些布局 xff0c 进行混合搭配 xff0c 最终的目的都是开发一
  • 响应式布局之viewport-超级简单

    之前文章CSS布局之详解 故里2130的博客 CSDN博客 上面的文章可以实现响应式布局 xff0c 根据浏览器的大小变化而变化 xff0c 但是相对于viewport来说 xff0c 之前的还是有点复杂 xff0c 而使用viewport
  • .net6API使用AutoMapper和DTO

    AutoMapper xff0c 是一个转换工具 xff0c 说到AutoMapper时 xff0c 就不得不先说DTO xff0c 它叫做数据传输对象 Data Transfer Object 通俗的来说 xff0c DTO就是前端界面需
  • 手机/移动端的UI框架-Vant和NutUI

    下面推荐2款手机 移动端的UI框架 其实还有很多的框架 xff0c 各个大厂都有UI框架 目前 xff0c 找来找去 xff0c 只有腾讯的移动端是setup语法写的TDesign xff0c 其他大厂 xff0c 虽然都是VUE3写的 x
  • 使用uniapp创建小程序和H5界面

    uniapp的介绍可以看官网 xff0c 接下来我们使用uniapp创建小程序和H5界面 xff0c 其他小程序也是可以的 xff0c 只演示创建这2个 xff0c 其实都是一套代码 xff0c 只是生成的方式不一样而已 uni app官网
  • 使用NutUI创建小程序和H5界面

    做开发的时间长了 xff0c 技术都是通用的 xff0c 创建小程序和H5界面有很多的UI xff0c 本章节演示使用NutUI来创建 xff0c 官网 xff0c NutUI 移动端 Vue3 小程序组件库 1 使用HBuilder X创
  • 如何开发微信小程序呢

    也许很多人对小程序 xff0c H5程序 xff0c Vue xff0c 网页程序 xff0c PC端程序认识比较模糊 xff0c 因为这些跨度非常的大 xff0c 很少人会一次性全部接触 xff0c 甚至只是听说过 xff0c 并不了解其
  • .NET6中使用GRPC详细描述

    Supported languages gRPC xff0c 官网 至于原理就不说了 xff0c 可以百度原理之后 xff0c 然后再结合代码 xff0c 事半功倍 xff0c 就能很好理解GRPC了 目录 一 简单使用 二 实际应用 一
  • spss统计分析基础教程(下)--自学

    目录 xff09 第十二章分布类型的检验12 1假设检验的基本思想12 2正态分布检验K S检验的原理 12 3二项分布检验12 4游程检验12 5蒙特卡罗方法 第十三章连续变量的统计推断 xff08 一 xff09 t检验13 1t检验概
  • uniapp学习记录

    目录 1 布局使用flex布局 2 rpx和界面自适应 xff0c 设计稿是750rpx 3 首页不显示tabBar 4 跳转页面 启动跳转页面 5 uniapp中页面生命周期 传值 6 颜色使用 7 字体使用 8 SCSS CSS中获取j
  • uniapp中调用.net6 webapi

    使用uniapp开发程序时 xff0c 不管是小程序 xff0c 还是H5界面 xff0c 它们只是一个显示界面 xff0c 也就是只充当前台界面 xff0c 那么我们后台使用 net6 webapi写业务逻辑 xff0c 然后前端访问后端
  • vue3中前端处理不同数据结构的JSON

    有时候 xff0c 后端返回的JSON数据格式 xff0c 是前端不需要的格式类型 xff0c 这时 xff0c 要么让后端修改 xff0c 你要什么格式 xff0c 那么让后端大哥哥给你返回什么格式 但是有时候不尽人意 xff0c 后端大
  • 在vue3中Element Plus切换主题

    一共2种方法 目录 第一种 第二种 第一种 暗黑模式 xff0c 使用useDark xff0c 可以不用安装Element Plus xff0c 只切换页面的背景颜色 xff0c 不改变Element Plus控件的颜色 xff0c 本案
  • IIS发布.net6 api+微信小程序/H5真机调试接口的流程

    我们创建 net6 api程序 xff0c 然后使用SqlSugar连接MySQL数据库 xff0c 再使用iis发布 xff0c 当然使用其他的也行 再开发一个微信小程序 xff0c 手机运行小程序 xff0c 手机运行H5 xff0c
  • 全栈开发小作品展示(有声音)

    不积跬步 xff0c 无以至千里 xff1b 不积小流 xff0c 无以成江海 目录 1 客户端 2 网站 3 小程序 4 H5演示 1 客户端 PC桌面 xff0c WPF 43 prism框架 xff0c 前后端分离 xff0c 主要是

随机推荐

  • rust学习

    Installation The Rust Programming Language https doc rust lang org book ch01 01 installation html 一 安装 安装了几个组件 curl prot
  • visual studio 2017出现MSB8020,MSB8036等SDK版本选择的错误

    1 xff0c 严重性 代码 说明 项目 文件 行 禁止显示状态 错误 MSB8020 无法找到 v140 的生成 xff1b 2 xff0c 严重性 代码 说明 项目 文件 行 禁止显示状态 错误 MSB8036 找不到 Windows
  • C++中循环include问题的讨论

    问题 C语言中未避免头文件的重复引用 xff0c 一般都会使用include guard 如pragma once或 ifndef等 xff0c 但这样做以后并不是万事大吉了 循环使用include可能会出现一些意想不到的错误 如果代码较为
  • flask+gevent+gunicorn+supervisor+nginx异步高并发部署

    背景 flask是一款同步阻塞框架 xff0c 在调用外部http服务时 xff0c 当前进程将阻塞 多进程模式下 xff0c 无法响应其他用户的请求 xff0c 本文则是研究的是如何利用gevent提升flask的并发能力 xff0c 以
  • 小白学SAS--自学笔记

    64 TOC 目录 xff09 第一章初识SAS 数据集的命名 数据导入 建立永久数据集 用菜单新建文件夹 xff0c 并与电脑上已有文件夹关联 用libname语句指定文件夹名 xff0c 并与电脑上已有文件夹关联 用data语句直接指定
  • http协议常用请求头与响应头

    请求头 xff1a Accept 用于告诉服务器 xff0c 客户机支持的数据类型 Accept Charset xff1a 用于告诉服务器 xff0c 客户机所采用的编码 Accept Encoding xff1a 用于告诉服务器 xff
  • mysqlId 不能自启的问题(错误代号2003)

    计算机服务里看下有没有mysql的服务 xff0c 如果有 xff0c 把服务的启动类型改为自动 xff1b 如果没有 xff0c 则要进入安装目录的bin文件夹双击mysqld exe启动mysql 然后 cmd到 Mysql的安装目录的
  • RabbitMQ学习笔记1-"Hello World!"simple模型

    simple模型是RabbitMQ队列模型中最简单的一个模型 如图 xff1a P 是我们的生产者 xff08 producer xff09 xff0c C 是我们的消费者 xff08 consumer xff09 中间的红色框是队列 xf
  • RabbitMQ学习笔记2-Work queues

    接下来学习第二种模型 xff0c Work queues模型 xff0c 如图所示 xff1a 该模型描述的是 xff1a 一个生产者 xff08 P xff09 向队列发送一个消息 xff0c 然后多个消费者 xff08 P xff09
  • RabbitMQ学习笔记3-Publish/Subscribe

    在这部分中 xff0c 我们会做一些完全不同的事情 我们会向多个消费者传递相同的信息 这种模式就是 发布 订阅 该模型中生产者从不将任何消息直接发送到队列 xff0c 生产者通常甚至不知道要将消息发送到哪个队列 xff0c 通常是 xff0
  • ssh -X 使用遇到的问题

    ssh可以在登录时通过 X选项开启远程服务的X服务 xff0c 这样服务器端的需要调用X服务的程序就能开启了 最简单的例子就是可以使用服务器段的gedit程序编译文件了 问题是这样的 xff1a 在IDL程序中有个write gif程序 x
  • Docker部署Gitlab和gitlab-runner,搭建一站式DevOps平台

    一 首次安装Gitlab并配置Gitlab runner CI CD Gitlab Docker 官方安装文档 xff1a https docs gitlab cn jh install docker html 设置Gitlab数据和配置挂
  • 打开 word 显示内存或磁盘空间不足 ,Word 无法显示所请求的字体

    打开word显示内存或磁盘空间不足 xff0c Word无法显示所请求的字体 使用360加速球优化一下 xff0c 恢复正常
  • 使用win10工具远程连接树莓派

    win10远程连接树莓派 1 使用ssh远程连接1 1系统烧录1 2 SSH登录 2 使用win10的mstsc工具远程连接2 1进入远程ssh后 xff0c 修改软件源 xff0c 否则太慢 xff08 清华软件源地址 https mir
  • 网络 - 笔记本无线转为有线

    工具 路由器一个 计算机两台C1和C2 场景说明 xff1a 将C1计算机的无线网络通过路由器转为有线网络 xff0c 并提供给C2计算机使用 第一步 xff1a 硬件搭建 连接C1和路由器 xff1a 将网线的A端插入路由器的WAN口 x
  • 医学案例统计分析与SAS应用--自学笔记

    目录 第二章医学研究设计与SAS实现科研设计思路样本含量估计实验设计 科研设计的sas实现完全随机设计随机区组设计析因设计关系型研究 第三章 统计描述与SAS分析统计描述及sas命令简介定量资料的统计描述分类资料的统计描述 第四章 定量资料
  • 计算机基础 - 左移、右移和计算逻辑

    左移 指的是位移动 xff0c 左移就是将数据位向左移动 xff0c 例如十进制10 二进制为0000 1010 左移4位后得到1010 0000 xff0c 转为十进制后为160 如果是左移5位 xff0c 那么超出部分被丢弃得到的就是0
  • C++ 二叉树实现词频分析

    通过二叉树存单词 xff0c 并且对总共的单词数量进行计数 xff0c 二叉树自适应的将出现频率高的单词往上移动以减少二叉树的搜索时间 代码如下 span class hljs comment genSplay h span span cl
  • C++ cout输出字符

    cout输出字符时 xff0c 可以使用单引号 xff1a cout lt lt span class hljs string 39 39 span lt lt endl span class hljs regexp span 输出分号 s
  • Linux 多进程多线程编程

    一 创建进程 1 进程号 进程号的类型是pid t xff08 typedef unsigned int pid t xff09 获得进程和父进程ID的API如下 xff1a include lt sys types h gt includ