操作系统

进程的五种状态

1:new 进程正在被创建,尚未达到ready状态

2:ready状态,进程已经获得除了cpu的一切其他资源----万事具备,只欠东风

3:running状态

4:waiting状态---正在等待获得其他资源--io资源等

5:结束状态

image.png

进程与线程的区别

进程是资源分配的基本单位,线程是任务执行的基本单位
线程的程序计算器、本地方法区、虚拟机栈是独立的,堆和方法区是共享的

image.png

进程通信

匿名管道

一般是父子进程或兄弟进程之间的通信,半双工模式,有固定的读端(fd[0])和写端(fd[1])


image.png

image.png
#include
#include

int main()
{
    int fd[2];  // 两个文件描述符
    pid_t pid;
    char buff[20];

    if(pipe(fd) < 0)  // 创建管道
        printf("Create Pipe Error!\n");

    if((pid = fork()) < 0)  // 创建子进程
        printf("Fork Error!\n");
    else if(pid > 0)  // 父进程
    {
        close(fd[0]); // 关闭读端
        write(fd[1], "hello world\n", 12);
    }
    else
    {
        close(fd[1]); // 关闭写端
        read(fd[0], buff, 20);
        printf("%s", buff);
    }

    return 0;
}
命名管道

不具有亲缘关系的进程也可以使用

消息队列

消息的链接表,独立于发送和接收线程,有特定的优先级,可以随机进行访问

#include 
// 创建或打开消息队列:成功返回队列ID,失败返回-1
int msgget(key_t key, int flag);
// 添加消息:成功返回0,失败返回-1
int msgsnd(int msqid, const void *ptr, size_t size, int flag);
// 读取消息:成功返回消息数据的长度,失败返回-1
int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);
// 控制消息队列:成功返回0,失败返回-1
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
#include 
#include 
#include 

// 用于创建一个唯一的key
#define MSG_FILE "/etc/passwd"

// 消息结构
struct msg_form {
    long mtype;
    char mtext[256];
};

int main()
{
    int msqid;
    key_t key;
    struct msg_form msg;

    // 获取key值
    if((key = ftok(MSG_FILE,'z')) < 0)
    {
        perror("ftok error");
        exit(1);
    }

    // 打印key值
    printf("Message Queue - Server key is: %d.\n", key);

    // 创建消息队列
    if ((msqid = msgget(key, IPC_CREAT|0777)) == -1)
    {
        perror("msgget error");
        exit(1);
    }

    // 打印消息队列ID及进程ID
    printf("My msqid is: %d.\n", msqid);
    printf("My pid is: %d.\n", getpid());

    // 循环读取消息
    for(;;)
    {
        msgrcv(msqid, &msg, 256, 888, 0);// 返回类型为888的第一个消息
        printf("Server: receive msg.mtext is: %s.\n", msg.mtext);
        printf("Server: receive msg.mtype is: %d.\n", msg.mtype);

        msg.mtype = 999; // 客户端接收的消息类型
        sprintf(msg.mtext, "hello, I'm server %d", getpid());
        msgsnd(msqid, &msg, sizeof(msg.mtext), 0);
    }
    return 0;
}
#include 
#include 
#include 

// 用于创建一个唯一的key
#define MSG_FILE "/etc/passwd"

// 消息结构
struct msg_form {
    long mtype;
    char mtext[256];
};

int main()
{
    int msqid;
    key_t key;
    struct msg_form msg;

    // 获取key值
    if ((key = ftok(MSG_FILE, 'z')) < 0)
    {
        perror("ftok error");
        exit(1);
    }

    // 打印key值
    printf("Message Queue - Client key is: %d.\n", key);

    // 打开消息队列
    if ((msqid = msgget(key, IPC_CREAT|0777)) == -1)
    {
        perror("msgget error");
        exit(1);
    }

    // 打印消息队列ID及进程ID
    printf("My msqid is: %d.\n", msqid);
    printf("My pid is: %d.\n", getpid());

    // 添加消息,类型为888
    msg.mtype = 888;
    sprintf(msg.mtext, "hello, I'm client %d", getpid());
    msgsnd(msqid, &msg, sizeof(msg.mtext), 0);

    // 读取类型为777的消息
    msgrcv(msqid, &msg, 256, 999, 0);
    printf("Client: receive msg.mtext is: %s.\n", msg.mtext);
    printf("Client: receive msg.mtype is: %d.\n", msg.mtype);
    return 0;
}
信号量

信号量是利用PV原语来实现进程同步

共享内存

效率最高,多个进程去对某一个内存进行访问

信号

信号:作为一种软中断,一个进程可以发出信号给操作系统,操作系统然后去通知另一个进程,然后该进程中断一下去执行
kill()函数主要用于向指定的进程或进程组发送信号

image.png

线程同步

线程同步:多个线程在竞争过程中,能保证保证代码顺序执行


image.png

1:互斥锁
pthread_mutex_lock就是上锁的函数,pthread_mutex_unlock就是解锁的函数

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int gTotalTickerNum = 20;

void *sellTicket(void *arg) {
  for (int i = 0; i < 20; i++) {
    pthread_mutex_lock(&mutex);
    if (gTotalTickerNum > 0) {
      sleep(1);
      printf("sell the %dth ticket\n", 20 - gTotalTickerNum + 1);
      gTotalTickerNum--;
    }
    pthread_mutex_unlock(&mutex);
  }
  return nullptr;
}

在多线程同步中的用到的比较多

image.png

Mutex相当于一把钥匙

image.png

2:条件变量
和互斥锁一起用
3:读写锁
写锁独占,读锁共享
4:信号量
信号量类似一个容纳n个人的房间,限制同时访问的量

image.png

管程

为什么引入monitor?
信号量保证不了执行的顺序,也可能导致错误
将共享变量和操作原语封装在一个对象中,保证去顺序执行这些操作


image.png

你可能感兴趣的:(操作系统)