线程同步与进程通信

线程同步

互斥量

  • 临界资源:在一段时间内只允许一个任务(线程或进程)访问资源。任务之间采用互斥的方式访问临界资源

  • 互斥量:pthread_mutex_t mutex; 初始化、加锁、解锁、销毁

    • 加锁:int pthread_mutex_lock(); int pthread_mutex_trylock();在访问临界资源前,对互斥量进行加锁。trylock()未加锁则加锁,加锁后不重复加锁。
    • 解锁:int pthread_mutex_unlock();访问完成后对互斥量解锁
    • 销毁:int pthread_mutex_destory();互斥量使用完毕后对互斥量进行销毁,释放资源。

条件变量

  • 任务同步:多个线程都要访问临界资源又要相互合作,一个任务的执行依赖与另一个任务的执行情况。

  • 条件变量:pthread_cond_t cond;和互斥量一起使用,允许线程以互斥的方式阻塞等待条件的发生即为同步关系

    • 触发条件变量的线程:互斥量加锁>>某一操作>>触发条件变量>>互斥量解锁
    • 等待条件变量的线程:互斥量加锁>>等待条件变量>>某一操作>>互斥量解锁
    • 销毁:pthread_cond_destory();条件变量不再使用后进行销毁,释放空间
    • 等待条件变量:pthread_cond_wait();使得调用进程进入阻塞状态,直到条件触发
    • 触发条件变量:pthread_cond_signal();/pthread_cond_broadcast();可触发并唤醒等待条件变量的线程
  • 条件变量与互斥量要配合使用

    • 条件变量的使用场景伴随着临界资源的使用

    • 在调用pthread_cond_wait();前需要使互斥量处于加锁状态,通过原子操作将调用线程放到该条件变量等待线程队列(临界资源)中

      //等待条件变量的操作
      pthread_mutex_lock();
      pthread_cond_wait();
      pthread_mutex_unlock();
      
  • 条件变量的使用

读写锁

  • 读写关系:读写互斥、写写互斥、读读不互斥

  • 读写锁:pthread_rwlock_t;

    • 加读锁:阻塞加锁pthread_rwlock_rdlock();/非阻塞加锁pthread_rwlock_tryrdlock();/限时加读锁pthread_rwlock_timedrdlock();
    • 加写锁:阻塞加锁pthread_rwlock_wrlock();/非阻塞加锁pthread_rwlock_trywrlock();/限时加读锁pthread_rwlock_timedwrlock();
    • 解锁:统一解锁函数,最近配对原则解锁pthread_rwlock_unlock();

进程通信

  • 管道和命名管道:文件的形式实现不同进程共享资源

  • XSI IPC机制:LINUX系统使用的进程通信机制

    功能信号量共享内存消息队列
    创建或打开一个IPC对象,获得对IPC机制的访问权semgetshmgetmsgget
    IPC操作:信号量操作;连接/释放共享内存;发送/接收消息semopshmat/shmdtmsgsnd/msgrcv
    IPC控制:获得/修改IPC对象状态,“删除”IPC对象semctlshmctlmsgctl

消息队列

  • 消息队列:消息的链表,有写或者读权限的进程可以按照一定的规则添加或者读取消息

  • 消息队列的操作sys/types.h sys/ipc.h sys/msg.h

    • 打开或创建消息队列对象:int msgget();
    • 从消息队列接收消息:int msgrcv();
    • 向消息队列发送消息:int msgsnd();
    • 消息队列控制操作:int msgctl();

信号量

  • 互斥信号量:任务之间互斥访问临界资源 初始值为1

  • 计数信号量:任务之间竞争访问共享资源 初始值大于1,表示共享资源个数

  • 二值信号量:任务之间的同步机制 初始值为0

  • 信号量的数据结构

    struct s
    {
        int count; //资源计数
        Queue queue; //任务阻塞队列
    };
    
    int init(); // 初始化
    int P(); // P操作
    int V(); // V操作
    
  • P操作:分配资源

    --s.count;
    if(s.count < 0)
    {
    	调用进程进入s.queue;
    	阻塞调用进程;
    }
    
  • V操作:释放资源

    ++s.count;
    if(s.count <= 0 )
    {
    	从阻塞队列s.queue中取出一个进程P;
    	进程P进入就绪队列;
    }
    
  • 信号量集的操作sys/types.h sys/ipc.h sys/sem.h

    • 创建或者打开信号量集对象int semget();

      #include<stdio.h>
      #include<sys/sem.h>
      #define MYKEY 0x1a0a //定一个ipc的key值
      int main()
      {
      	int semid;
      	semid = semget(MYKEY,1,IPC_CREAT|IPC_R|IPC_W|IPC_M); //创建一个信号量集对象
      	printf("semid = %d\n",semid);
          return 0;
      }
      
    • 信号量PV操作int semop();:根据参数short sem_op;判断执行的操作类型

      • sem_op > 0:信号量V操作,增加信号量的值
      • sem_op < 0:信号量P操作,减少信号量的值
      • sem_op = 0:对信号量的当前值是否为0的测试
      //实现P操作
      static int semaphore_v(void)
      {
      	struct sembuf sem_b;
      	sem_b.sem_num = 0; //信号量编号
      	sem_b.sem_op = -1; // P操作
      	sem_b.sem_fg = SEM_UNDO; //在进程没释放信号量而退出时,系统自动释放该进程中未释放的信号量
      	if(semop(sem_id, &sem_b,1) == -1)
      	{
      		fprintf(stderr,"semaphore_p failed\n");
      		return 0;
      	}
      	return 1;
      }
      
      //实现V操作
      static int semaphore_v(void)
      {
      	struct sembuf sem_b;
      	sem_b.sem_num = 0;
      	sem_b.sem_op = 1; // V操作
      	sem_b.sem_fg = SEM_UNDO;
      	if(semop(sem_id, &sem_b,1) == -1)
      	{
      		fprintf(stderr,"semaphore_v failed\n");
      		return 0;
      	}
      	return 1;
      }
      
    • 信号量控制int semctl();int cmd;控制命令参数

      • 对信号量集的控制命令:IPC_RMID删除;IPC_SET设置参数;IPC_STAT获取参数;IPC_INFO获取系统信息
      • 对信号量的控制命令:SETVAL设置信号量的值;GETVAL获取信号量的值;GETPID获取信号量拥有者的PID值
      //信号量初始化
      int init_sem(int sem_id, int init_value)
      {
      	union semun_sem_union;
      	sem_union.val = init_value;
      	if(semctl(sem_id,0,SETVAL,sem_union) == -1)
      	{
      		perror("Initialize semaphore");
      		return -1;
      	}
      	return 0;
      }
      
      //从系统中删除信号量
      int del_sem(int sem_id)
      {
      	union semun sem_union;
      	if(semctl(sem_id,0,IPC_RMID,sem_union) == -1)
      	{
      		perror("Initialize semaphore");
      		return -1;
      	}
      }
      

共享内存

  • 共享内存:不同进程可以将同一段内存空间链接到自己的地址空间中,类似物理空间中的全局变量

  • 共享内存的操作sys/types.h sys/ipc.h sys/shm.h

    • 创建或者打开共享内存对象int shmget();
    • 将共享内存链接到调用的进程的地址空间void *shmat();
    • 删除进程的共享内存链接int shmdt();
    • 对共享内存的操作int shmctl();
  • 共享内存应用–生产者/消费者问题

    //缓存池结构
    struct BufferPool
    {
    	char Buffer[5][100];
    	int index[5];
    };
    
GitHub 加速计划 / li / linux-dash
6
1
下载
A beautiful web dashboard for Linux
最近提交(Master分支:4 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐