sem.c
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/sem.h>
union semun
{
int val;
struct semid_ds *buf;
unsigned short *arry;
};
static int sem_id = 0;
static int set_semvalue();
static void del_semvalue();
static int semaphore_p();
static int semaphore_v();
int main(int argc, char *argv[])
{
char message = 'X';
int i = 0;
// 创建信号量
sem_id = semget((key_t) 1234, 1, 0666 | IPC_CREAT);
printf("semid= %d \n", sem_id);
if (argc > 1)
{
// 程序第一次被调用,初始化信号量
if (!set_semvalue())
{
fprintf(stderr, "Failed to initialize semaphore\n");
exit(EXIT_FAILURE);
}
// 设置要输出到屏幕中的信息,即其参数的第一个字符
message = argv[1][0];
sleep(2);
}
for (i = 0; i < 10; ++i)
{
// 进入临界区
if (!semaphore_p())
{
exit(EXIT_FAILURE);
}
// 向屏幕中输出数据
printf("%c", message);
// 清理缓冲区,然后休眠随机时间
fflush(stdout);
sleep(rand() % 3);
// 离开临界区前再一次向屏幕输出数据
printf("%c", message);
fflush(stdout);
// 离开临界区,休眠随机时间后继续循环
if (!semaphore_v())
{
exit(EXIT_FAILURE);
}
sleep(rand() % 2);
}
sleep(10);
printf("\n%d - finished\n", getpid());
if (argc > 1)
{
// 如果程序是第一次被调用,则在退出前删除信号量
sleep(3);
del_semvalue();
}
exit(EXIT_SUCCESS);
}
static int set_semvalue()
{
// 用于初始化信号量,在使用信号量前必须这样做
union semun sem_union;
sem_union.val = 1;
if (semctl(sem_id, 0, SETVAL, sem_union) == -1)
{
return 0;
}
printf("semctl sucess\n");
return 1;
}
static void del_semvalue()
{
// 删除信号量
union semun sem_union;
if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
{
fprintf(stderr, "Failed to delete semaphore\n");
}
}
static int semaphore_p()
{
// 对信号量做减1操作,即等待P(sv)
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;//P()
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_p failed\n");
return 0;
}
return 1;
}
static int semaphore_v()
{
// 这是一个释放操作,它使信号量变为可用,即发送信号V(sv)
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1; // V()
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_v failed\n");
return 0;
}
return 1;
}
king@ubuntu:~/share/ms_examples/sem$ ./sem 0 & ./sem
[1] 368505
semid= 6
semid= 6
semctl sucess
XXXX00XX0000XX00XX00XX00XX00XX00XX0000XX
368505 - finished
368506 - finished
进程互斥
_public.h
#ifndef __PUBLIC_HH
#define __PUBLIC_HH 1
#include <iostream>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <cstdlib>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/sem.h>
using namespace std;
template <class TT, int MaxLength>
class squeue
{
private:
bool m_inited;
TT m_data[MaxLength];
int m_head;
int m_tail;
int m_length;
squeue(const squeue &) = delete;
squeue &operator=(const squeue &) = delete;
public:
void init()
{
if(m_inited !=true)
{
m_head = 0;
m_tail = MaxLength - 1;
m_length = 0;
memset(m_data, 0, sizeof(m_data));
m_inited = true;
}
}
squeue() { init();}
bool push(const TT &ee){
if(full() == true){
cout<< "循环队列已满,入队失败。\n"; return false;
}
m_tail=(m_tail+1)%MaxLength;
m_data[m_tail]= ee;
m_length++;
return true;
}
int size(){
return m_length;
}
bool empty()
{
if(m_length == 0) return true;
return false;
}
bool full()
{
if(m_length == MaxLength) return true;
return false;
}
TT &front(){
return m_data[m_head];
}
bool pop()
{
if(empty() == true) return false;
m_head=(m_head+1)%MaxLength;
m_length--;
return true;
}
void printqueue()
{
for(int ii=0; ii< size(); ii++){
cout<< "m_data[" << (m_head+ii)%MaxLength<<"],value="\
<< m_data[(m_head+ii)%MaxLength] << endl;
}
}
};
class csemp
{
private:
union semun
{
int val;
struct semid_ds *buf;
unsigned short *arry;
};
int m_semid;
short m_sen_flg;
csemp(const csemp&)=delete;
csemp &operator=(const csemp&)=delete;
public:
csemp():m_semid(-1){}
bool init(key_t key, unsigned short value=1, short sem_flg = SEM_UNDO);
bool wait(short sem_op = -1);
bool post(short sem_op = 1);
int getvalue();
bool destroy();
~csemp(){}
};
bool csemp::init(key_t key, unsigned short value, short sem_flg){
if(m_semid != -1) return false;
m_sen_flg = sem_flg;
if((m_semid = semget(key, 1, 0666)) == -1)
{
if(errno == ENOENT)
{
if((m_semid = semget(key, 1, 0666 | IPC_CREAT| IPC_EXCL)) == -1)
{
if(errno == EEXIST)
{
if(-1 == (m_semid = semget(key, 1, 0666)))
{
perror("init 1 semget()"); return false;
}
return true;
}
else
{
perror("init 2 semget()"); return false;
}
}
union semun sem_union;
sem_union.val = value;
if( semctl(m_semid, 0, SETVAL, sem_union)< 0)
{
perror("init semctl()");
return false;
}
}
else
{
perror("init 3 semget()"); return false;
}
}
return true;
}
bool csemp::wait(short value){
if(m_semid == -1) return false;
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = value;
sem_b.sem_flg = m_sen_flg;
if(semop(m_semid, & sem_b, 1) == -1)
{
perror("p semop()");
return false;
}
return true;
}
bool csemp::post(short value){
if(m_semid == -1) return false;
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = value;
sem_b.sem_flg = m_sen_flg;
if(semop(m_semid, & sem_b, 1) == -1)
{
perror("p semop()");
return false;
}
return true;
}
int csemp::getvalue(){
return semctl(m_semid, 0, GETVAL);
}
bool csemp::destroy()
{
if(m_semid == -1) return false;
if(semctl(m_semid, 0, IPC_RMID) == -1)
{
perror("destroy semctl()");
return false;
}
return true;
}
#endif
#include "_public.h"
struct stgirl
{
int no;
char name[51];
};
int main(int argc, char *argv[])
{
if(argc !=3 )
{
cout<< "Using: ./shm_samp no name\n";
return -1;
}
//1. 创建共享内存 键值key为0x5005
int shmid = shmget(0x5005, sizeof(stgirl), 0640|IPC_CREAT);
if(shmid == -1)
{
cout<< " shmget(0x5005 failed. \n";
return -1;
}
cout<< " shmid=" << shmid <<endl;
//2.把共享内存连接到当前进程的地址空间
stgirl *ptr = (stgirl *)shmat(shmid, 0, 0);
if(ptr == (void*)-1 )
{
cout<< " shmat() failed. \n";
return -1;
}
//创建、初始化二元信号量
csemp mutex;
if(mutex.init(0x5005) == false)
{
cout<< "mutex.init(0x5005) failed. \n";
return -1;
}
cout<<"申请加锁。。。\n";
mutex.wait();//申请加锁
cout<<"申请加锁成功。\n";
//3.使用共享内存对共享内存进行读写
cout<< "原值:no="<< ptr->no << ",name ="<< ptr->name <<endl;
ptr->no = atoi(argv[1]);
strcpy(ptr->name, argv[2]);
cout<< "新值:no="<< ptr->no << ",name ="<< ptr->name <<endl;
sleep(10);
mutex.post();//解锁
cout<<"解锁。\n";
//4.把共享内存从当前进程分离
shmdt(ptr);
//5.删除共享内存
#if 0
if(shmtl(shmid, IPC_RMID) == -1)
{
cout<< " shmtl() failed. \n";
return -1;
}
#endif
return 0;
}
xshell开2个窗口 进行测试
king@ubuntu:~/share/ms_examples/sem$ ./sem_samp 1 冰冰
shmid=5
申请加锁。。。
申请加锁成功。
原值:no=1,name =冰冰
新值:no=1,name =冰冰
解锁。
king@ubuntu:~/share/ms_examples/sem$ ./sem_samp 2 幂幂
shmid=5
申请加锁。。。
申请加锁成功。
原值:no=1,name =冰冰
新值:no=2,name =幂幂
解锁。
#删除信号量
ipcrm -s 5