基本概念:
操作系统
出现原因:为解决程序员掌握计算机系统硬件细节而为计算机安装的一层软件
作用:为用户提供可视化计算机硬件模型、提供计算机硬件接口,管理硬件资源
内核
地位:是操作系统中最重要的核心程序
作用:管理计算机硬件,分配内存资源
系统调用
出现原因:防止程序间运行冲突,用户只在用户态条件下运行
作用:内核的入口,进入内核,通过内核访问硬件
进程
定义:程序运行中需要分配资源,需要对进程进行资源管理
作用:是操作系统进行资源分配和调度的基本单位
虚拟内存
定义:内核为进程分配一虚拟内存,后经操作系统翻译后分配到真实物理内存中,这种内存分配方式成为虚拟内存
作用:防止程序间内存分配冲突和运行冲突
并发
定义:CPU在经历多个进程时会先执行一个程序,在等待程序运行完毕期间会执行另一个程序,当第一个进程结束时会返回到该结束进程中,这种操作叫做并发,宏观上是一个时间段内运行了多个程序,但在微观内是CPU在一个时间段内只运行一个程序
文件描述符
Linux中打开/创建文件会从操作系统中返回一个int值,被称为文件描述符,通常是非负整数,在一个进程启动后,会默认打开三个文件描述符,分别是0(标准输入)1(标准输出)2(标准错误)
通过open打开或创建文件时会得到一个在文件描述表中未使用的最小的文件描述符
———————————————————————————————————————————
进程1 fork() [1] && //父进程
进程2 fork() [0] && //子进程 ->短路 结束
进程3 fork() [1] && fork() [1] // &&右侧fork() [1] ->fork() [0] 结束
进程4 fork() [1] && fork() [1] --> 1 && 1 执行函数体内容,fork(1) -> fork(0) 结束
一共有四个进程,打印四个end
———————————————————————————————————————————
进程1 fork() [1] //父进程 -> 1 || (短路) -> if(1) > //执行函数体
进程2 fork() [1] -> fork() [0] 结束
进程3 fork() [0] //子进程 因为父进程为1 ,所以 0 || 1,fork() [0] || fork() [1]
进程4 fork() [1] -> fork() [0] 结束
进程5 因为0 || 1 执行函数体内容 fork(1) -> fork(0) 结束
一共有五个进程,打印五个end\n
———————————————————————————————————————————
进程1 fork() [1] 1 || X短路,if(1) ->//进入函数体 fork() [1] -> fork() [0]
进程2 短路后0 || 1 -> fork() [0] || fork() [1]
进程3 进程2 || 右侧fork() [1] -> fork() [0] 结束
进程4 进程1 fork() [1] -> fork() [0]结束
进程5 ,进程2 || 右侧fork() [1] -> fork() [0]结束
进程6 if(1 && 1) 进入函数体 fork() [1] -> fork() [0]结束
一共六个进程,打印六个end\n
——————————————————————————————————————————
生产者 / 消费者模型 (条件变量 / 互斥量)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
#include<fcntl.h>
#include<time.h>
pthread_mutex_t mutex;//互斥锁
pthread_cond_t cond;//条件变量
//初始化链表
struct Node{
int number;//数据域
struct Node* next;//指针域
};
struct Node* head;//创建头节点
struct Node* append_node(int number){//添加节点
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
new_node->number = number;
new_node->next = head;
head = new_node;
return head;
}
int pop_head_node(){
struct Node* temp = head;
int number = temp->number;
head = head->next;
free(temp);
return number;
}
void* producer(void* args)
{
while(1)
{
pthread_mutex_lock(&mutex);
append_node(rand() % 500 + 1);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
void* consumer(void* args)
{
while(1)
{
pthread_mutex_lock(&mutex);
while(head == NULL)
{
pthread_cond_wait(&cond,&mutex);
}
printf("Number = %d\n",pop_head_node());
pthread_mutex_unlock(&mutex);
}
}
int main(int argc, char* argv[])
{
srand(time(NULL));//种随机种子
pthread_t tid1;//创建tid2 tid2线程编号
pthread_t tid2;
pthread_create(&tid1,NULL,producer,NULL);//创建线程
pthread_create(&tid2,NULL,consumer,NULL);
pthread_join(tid1,NULL);//返回值
pthread_join(tid2,NULL);
return 0;
}
epoll
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <pthread.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/epoll.h>
#define SERVER_PORT 8000
#define BUFFER_SIZE 1024
#define EVENT_SIZE 1024
int main(int argc, char* argv[]){
int lfd = socket(AF_INET,SOCK_STREAM,0); //创建套接字
if(lfd == -1){
perror("socket error");
exit(1);
}
struct sockaddr_in serveraddr,clientaddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERVER_PORT);
serveraddr.sin_addr.s_addr = INADDR_ANY;
int ret = bind(lfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
if(ret == -1){
perror("bind error");
exit(1);
}
ret = listen(lfd,64);
if(ret == -1){
perror("listen error");
exit(1);
}
socklen_t addr_len = sizeof(clientaddr);
int cfd = -1;
char buf[BUFFER_SIZE];
int read_ret = 0;
char clientip[32];
int epoll_ret = 0;
int epfd = epoll_create(64); //创建epoll对象
struct epoll_event event; //创建结构体对象
struct epoll_event events[EVENT_SIZE]; //创建结构体数组
event.events = EPOLLIN; //设置监听事件为读事件
event.data.fd = lfd; //设置监听文件描述符
epoll_ctl(epfd,EPOLL_CTL_ADD,lfd,&event); //将lfd增加到epoll对象里
while(1){
epoll_ret = epoll_wait(epfd,events,EVENT_SIZE,0);
if(epoll_ret < 0){
perror("epoll error");
exit(1);
}
else if(epoll_ret == 0){
}
else{
for(int i = 0; i < epoll_ret;i++){
int fd = events[i].data.fd;
if(events[i].events & EPOLLIN){
if(fd == lfd){ //判断是否是通信套接字
cfd = accept(lfd,(struct sockaddr*)&clientaddr,&addr_len);
printf("有新的客户端建立连接:IP=%s, PORT=%d\n",inet_ntop(AF_INET,&clientaddr.sin_addr.s_addr,clientip,sizeof(clientip)),ntohs(clientaddr.sin_port));
if(cfd < 0){
perror("accept error");
exit(1);
}
else{
event.events = EPOLLIN;
event.data.fd = cfd;
epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&event);
}
}
else{ //客户端套接字
read_ret = read(fd,buf,BUFFER_SIZE);
if(read_ret < 0){
perror("read error");
exit(1);
}
else if(read_ret == 0){
printf("客户端断开连接\n");
epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);
close(fd);
}
else{
write(STDOUT_FILENO,buf,read_ret);
write(fd,buf,read_ret);
}
}
}
}
}
}
}