进程
1.查进程
ps命令查找与进程相关的PID号:
ps a 显示现行终端机下的所有程序,包括其他用户的程序。
ps -A 显示所有程序。
ps c 列出程序时,显示每个程序真正的指令名称,而不包含路径,参数或常驻服务的标示。
ps -e 此参数的效果和指定"A"参数相同。
ps e 列出程序时,显示每个程序所使用的环境变量。
ps f 用ASCII字符显示树状结构,表达程序间的相互关系。
ps -H 显示树状结构,表示程序间的相互关系。
ps -N 显示所有的程序,除了执行ps指令终端机下的程序之外。
ps s 采用程序信号的格式显示程序状况。
ps S 列出程序时,包括已中断的子程序资料。
ps -t<终端机编号> 指定终端机编号,并列出属于该终端机的程序的状况。
ps u 以用户为主的格式来显示程序状况。
ps x 显示所有程序,不以终端机来区分。
2.杀进程
使用kill命令结束进程:kill xxx(PID/进程的名字)
3.exce()族函数的使用
4.fork
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
fork()
函数是用于创建一个新的进程的系统调用。调用 fork()
后,会产生两个几乎完全相同的进程,一个是父进程,另一个是子进程。这两个进程在执行时拥有相同的程序代码、数据以及状态。
在 fork()
调用之后,父子进程会有不同的返回值:
在父进程中,fork()
返回子进程的PID(Process ID),也就是新创建子进程的标识符。
在子进程中,fork()
返回0。
此外,在父子进程中还可以通过获取PPID(Parent Process ID)来获得对方的信息。具体来说:
在父进程中,获取到的PPID就是它自己的PID。
在子进程中,获取到的PPID就是它父进程的PID。
5.sleep
其中,Sleep()里面的单位,是以毫秒为单位,所以如果想让函数滞留1秒的话,应是Sleep(1000);
6.wait
‘Z’是僵尸进程
#include <sys/types.h>
#include <sys/wait.h>
父对子负责,子进程结束后,先杀死子进程,再杀死父进程
进程的链接/通信
通过通道
未命名通道 - pipe
头文件
#include <unistd.h>
参数
int pipe(int filedes[2]);
描述:
pipe
函数用于创建一个无名管道,它返回两个文件描述符,分别对应于管道的读端和写端。数据写入管道的写端可以被从管道的读端读取。通常,一个进程创建管道后,调用 fork
创建子进程,子进程关闭写端,父进程关闭读端,这样就可以在它们之间实现通信。
两个文件描述符
filedes[0]子
filedes[1]父
例子
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#define BUFFER 20
#define NUMBER 20
int main(){
int fd[2];//fd[0]读fd[1]写
pid_t pid;
char buffer[BUFFER];
char number[NUMBER];
if(pipe(fd)){
perror("pipe error:");
exit(0);
}
pid = fork();//先pipe后fork 因为fork会创建一个一样进程,这样就是两个进程了
if(pid == 0){
close(fd[0]);
scanf("%s",buffer);
write(fd[1],buffer,BUFFER);
exit(0);
close(fd[1]);
}
else{//父接收
close(fd[1]);
read(fd[0],number,NUMBER);
printf("输出结果:%s\n",number);
close(fd[0]);
}
return 0;
}
命名通道 - mkfifo
头文件
#include <sys/types.h>
#include <sys/stat.h>
参数
int mkfifo(const char *pathname, mode_t mode);
描述:
mkfifo
函数用于创建一个命名管道,可以通过文件系统中的路径名进行访问。它返回 0 表示成功,-1 表示失败。通常,一个进程通过调用 open
打开一个命名管道文件,然后进行读写操作。
例子
#include <sys/types.h>
#include <sys/stat.h>
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
#define BUFFER 20
int main(){
pid_t pid;
int fd;
char buffer[BUFFER];
mkfifo("datafile",07777);//可读可写可执行
pid = fork();
if(pid == 0){
char s[] = "helloworld\n";
fd = open("datafile",O_WRONLY);
write(fd,s,sizeof(s));
exit(0);
}
else{
fd = open("datafile",O_RDONLY);
read(fd,buffer,sizeof(buffer));
printf("输出:%s\n",buffer);
}
return 0;
}
消息队列
消息队列是一种进程间通信的机制,用于在不同进程之间传递消息。它是一种先进先出(FIFO)的数据结构,消息发送者将消息放入队列的尾部,而消息接收者则从队列的头部获取消息。消息队列提供了一种松散耦合的通信方式,允许不同的进程在不共享内存的情况下进行通信。
共享内存
共享内存是一种用于进程间通信的机制,允许多个进程访问同一块内存区域。不同于消息队列,共享内存是一种更为直接和高效的通信方式,因为多个进程可以直接读写共享的内存区域,而无需通过中间的消息传递。
Domain Socket
线程主要讲这个
线程
进程是由线程组成的(至少一个)
pthread_create
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
(1)tidp:事先创建好的pthread_t类型的参数。成功时tidp指向的内存单元被设置为新创建线程的线程ID。
(2)attr:用于定制各种不同的线程属性。通常直接设为NULL。
(3)start_rtn:新创建线程从此函数开始运行。无参数是arg设为NULL即可。
(4)arg:start_rtn函数的参数。无参数时设为NULL即可。有参数时输入参数的地址。当多于一个参数时应当使用结构体传入
返回值 成功的话 -> 0
pthread_exit
#include <pthread.h>
void pthread_exit(void *retval);
只适合终止自己的线程
pthread_cancel
#include <pthread.h>
int pthread_cancel(pthread_t thread);
终止其他的线程
return 0; 也可以终止
pthread_join
等待
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
例子
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#define LEFT 3000000
#define RIGHT 3000200
static void * thr_prime(void *p);
int main(){
pthread_t tid[RIGHT-LEFT+1];
int i,err;
for(i = LEFT;i<=RIGHT;i++){
err = pthread_create(tid+(i-LEFT),NULL,thr_prime,(void *)&i);
if(err!=0){
fprintf(stderr,"线程创建失败");
exit(0);
}
}
for(i = LEFT;i<=RIGHT;i++){
pthread_join(tid[i-LEFT],NULL);
}
}
static void * thr_prime(void *p){
int j;
int mark = 1;
// int i =(int)p;注意解决这个问题
int i = *((int *)p);
for(j= 2;j<=i/2;j++){
if(i%j==0){
mark = 0;
break;
}
}
if(mark){
printf("%d\n",i);
}
pthread_exit(NULL);
}
int i = (int)p;
这是一种直接的指针到整数的转换,将指针
p
直接转换为整数类型。这种转换可能导致信息丢失,因为指针通常比int
类型的整数更长。这种转换在某些情况下可能会导致错误,因为指针可能表示的是一个内存地址,而将其强制转换为整数可能不会产生有意义的结果。int i = \*((int \*)p);
这是一种间接的指针到整数的转换。首先,将
p
强制转换为int *
类型的指针,然后使用解引用运算符*
获取指针指向的值。这样的操作通常用于从指针所指向的内存位置读取数据,而不是将指针本身转换为整数。
Domain Socket
域套接字,也称为Unix套接字,提供了同一台主机上的进程进行通信的一种方法。与常规(Internet)套接字不同,域套接字存在于文件系统中,通过文件路径而不是IP地址和端口进行标识。
以下是在Linux中使用域套接字的基本概述:
创建域套接字: 要创建域套接字,可以使用
socket()
系统调用,指定AF_UNIX
地址族:cCopy code int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
为套接字绑定名称: 创建套接字后,需要为其绑定一个名称。名称是文件系统中的文件路径。这可以通过
bind()
系统调用完成:cCopy codestruct sockaddr_un addr; addr.sun_family = AF_UNIX; strcpy(addr.sun_path, "/tmp/my_socket"); bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
监听连接(对于SOCK_STREAM): 如果使用流式套接字(
SOCK_STREAM
),可以监听传入的连接:cCopy code listen(sockfd, backlog);
接受连接(对于SOCK_STREAM): 使用
accept()
系统调用接受传入连接:cCopy code int newsockfd = accept(sockfd, (struct sockaddr*)&cli_addr, &clilen);
发送和接收数据: 对于流式套接字,可以使用
send()
和recv()
发送和接收数据。对于数据报套接字(SOCK_DGRAM
),可以使用sendto()
和recvfrom()
。关闭套接字: 最后,在完成后关闭套接字:
cCopy code close(sockfd);
清理: 如果程序退出或需要清理套接字文件,可以使用
unlink()
从文件系统中删除套接字文件:cCopy code unlink("/tmp/my_socket");