Linux 下的同步与互斥

同步与互斥

  同步发生在不同调度单位中(线程/进程),用来保证调度单位的时序性,比如生产者消费者模型中,消费者必须在生产者产出后才能消费,它们是存在先后顺序的。
  互斥用来发生在同一时间只能有一个调度单位去临界区(临界区指一段公共代码)执行相应逻辑,比如在多线程下的消费者生产者模型下,多个消费者消费的时候,需要互斥,因为消费这个动作不是原子的,所以可能俩个线程消费一个资源。

Linux下的同步与互斥
  1. 互斥锁(pthread_mutex)
  2. 条件变量(pthread_condition)
  3. 信号量(sem)
  4. 读写锁
  5. 自旋锁
  6. 大内核锁
信号量
semget
int semget(key_t key ,int nsems , int semflg)
key_t 标识ipc资源的一个键值
nsems: 信号集中信号量的个数
semflg:权限位与创建文件基本一致(664,666)
它用来创建一个信号量集,返回值大于0的时候,返回信号量集的标识符,
这个标识符后面的操作函数需要用到,失败返回-1
semctl
int semctl( int semid , int semnum , int cmd , ...)
cmd : 
SETVAL : 设置对应下标信号量的值
GETVAL : 得到信号量集中对应下标的信号量的值
SETALL : 设置数组初始化
GETALL : 将信号量集内容copy数组中。
IPC_STAT : 将semid_ds中的数据 初始化为 当前信号集的当前值
IPC_SET : 在权限的前提下,把信号量集的当前关联值设置为 semid_ds中给出的值
IPC_RMID :删除当前信号量集
最后一个可变参数是 
union semun{
int  val;  SETVAL的时候用
struct semid_ds * buf; IPC_STAT/SET 使用
unsigned short array;  SETALL的时候用
struct seminfo * _buf; IPC_INFO的时候用
}
成功返回0 , 失败返回-1.

1.初始化信号量集的时候用该函数
2.信号量是POSIX的进程间通信的一种方式,所以随内核,如果我们不释放造成资源泄露。

semop
int  semop( int semid, struct sembuf [] sops , unsigned nsops);
semid:前面讲的标识符
sops : sembuf 数组
nsops : 数组大小
成功返回0 失败-1
struct sembuf {
           unsigned short sem_num;  /* semaphore number */
           short          sem_op;   /* semaphore operation */
           short          sem_flg;  /* operation flags */
}
sem_flg : SEM_UNDO 可以防止死锁在进程退出的时候,防止没有规划信号量计数
          SEM_UNWAIT 当信号量为0的时候,P操作时返回 EAGIAN 不阻塞。

这个函数用来PV操作的,P申请资源对对应信号量减1 , V释放资源对相应信号量加1。

二元信号量(相当于互斥锁)代码
COMM.H
#ifndef _COMM_H
#define _COMM_H

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
#include <sys/wait.h>

#define PATHNAME "."
#define PROJ_ID 0x6666
union semun {
   int              val;    /* Value for SETVAL */
   struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
   unsigned short  *array;  /* Array for GETALL, SETALL */
   struct seminfo  *__buf;  /* Buffer for IPC_INFO
    ¦   ¦   ¦   ¦   ¦   ¦   ¦  (Linux-specific) */
};

int createSemSet( int nums );
int initSem ( int semid , int nums , int initVal);
int getSemSet ( int nums);
int P (int semid , int who);
int V (int semid , int who);
int destroySemSet ( int semid);

#endif

COMM.CC
#include "comm.h"

static int commSemSet ( int nums , int flags )
{
    key_t key = ftok(PATHNAME,PROJ_ID);
    if(key < 0){
    ¦   perror("ftok");
    ¦   return -1;
    }
    int semid = semget(key , nums , flags);
    if(semid < 0){ 
    ¦   perror("semget");
    ¦   return -2; 
    }   
    return semid;
}

int createSemSet ( int nums )
{
    return commSemSet ( nums , IPC_CREAT|IPC_EXCL|0666);
}

int getSemSet ( int nums )
{
    return commSemSet ( nums , IPC_CREAT);
}

int  initSem(int semid , int nums , int initVal)
{
    union semun _un;
    _un.val  =  initVal;
    if(semctl(semid , nums , SETVAL ,_un)==-1)
    {
    ¦   perror("semctl");
    ¦   return -4;
    }
    return 0;
}

static int commPV( int semid ,int who ,int op)
{
    ¦struct sembuf _buf;
    ¦_buf.sem_num = who;
    ¦_buf.sem_op = op;
    ¦_buf.sem_flg = SEM_UNDO;
    ¦if(semop(semid , &_buf , 1)==-1)
    {
    ¦   perror("semop");
    ¦   return -5;
    }
    ¦return 0;
}
int P ( int semid , int who)
{
    return commPV(semid,who,-1);
}
int V ( int semid , int who)
{
    return commPV(semid,who,1);
}
int destroySemSet(int semid)
{
    if(semctl(semid,0,IPC_RMID) < 0){
    ¦   perror("semctl");
    ¦   return -6;
    }
    return 0;
}

main.cc
#include "comm.h"

int main()
{
    int semid = createSemSet(1);
    initSem(semid , 0 ,1);
    pid_t id = fork();
    if(id == 0)
    {   
    ¦   int _semid = getSemSet(0);
    ¦   while(1)
    ¦   {   
    ¦   ¦   P(_semid,0);
    ¦   ¦   printf("A");
    ¦   ¦   fflush(stdout);
    ¦   ¦   usleep (100000);
    ¦   ¦   printf("A");
    ¦   ¦   fflush(stdout);
    ¦   ¦   usleep (100000);
    ¦   ¦   V (_semid , 0 );
    ¦   }   
        }
    else
    {
    ¦   while(1)
    ¦   {
    ¦   ¦   P (semid , 0);
    ¦   ¦   printf("B");
    ¦   ¦   fflush(stdout);
    ¦   ¦   usleep (100000);
    ¦   ¦   printf("B");
    ¦   ¦   fflush(stdout);
    ¦   ¦   usleep (100000);
    ¦   ¦   V(semid , 0);
    ¦   }
    ¦   waitpid(id,NULL,-1);
    }
    destroySemSet(semid);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值