操作系统实验资料搜集:信号量,生产者消费者,读者写者等

Linux C 进程间通信: 生产者消费者问题

转自http://www.cnblogs.com/lycheng/archive/2011/11/23/2260656.html

有两个生产者,一个写入大写字母,另一个写入小写。

有三个消费者,一个消费大写字母,一个消费小写字母,还有一个不分大小写消费。

 

复制代码
#include <stdlib.h>
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <linux/sem.h>
#include <sys/types.h>

#define MAX_PRODUCTS 10
struct sembuf buf;

int down(int sem_id)
{
buf.sem_num = 0;
buf.sem_op = -1;
buf.sem_flg = SEM_UNDO;
if (semop(sem_id, &buf, 1) == -1)
{
perror("Down failed!/n");
return 0;
}
return 1;
}
int up(int sem_id)
{
buf.sem_num = 0;
buf.sem_op = 1;
buf.sem_flg = SEM_UNDO;
if (semop(sem_id, &buf, 1) == -1)
{
perror("Up failed!/n");
return 0;
}
return 1;
}

void main()
{
union semun arg;
pid_t producer1, producer2;
pid_t consumer1, consumer2, consumer3;

int mutex;
int full;
int empty;
char *buffer;

// 共享内存
buffer = (char*) mmap(NULL, sizeof(char) * MAX_PRODUCTS,
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
int i;
for (i = 0; i < MAX_PRODUCTS; i++)
buffer[i] = '';

// 创建信号量
mutex = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
full = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
empty = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
arg.val = 1;
if (semctl(mutex, 0, SETVAL, arg) == -1)
{
perror("set the mutex error\n");
return;
}
arg.val = 0;
if (semctl(full, 0, SETVAL, arg) == -1)
{
perror("set the full error\n");
return;
}
arg.val = MAX_PRODUCTS;
if (semctl(empty, 0, SETVAL, arg) == -1)
{
perror("set the empty error/n");
return;
}

if ((producer1 = fork()) == 0)
{
// 写入大写字母
while (1)
{
down(empty);
down(mutex);
srand(time(NULL));
int offset = rand() % 26;
char item = 'A' + offset;
int j;
for (j = 0; j < MAX_PRODUCTS; j++)
{
if (buffer[j] == '')
{
buffer[j] = item;
printf("Producer A insert letter: %c\n", item);
break;
}
}
up(mutex);
up(full);
sleep(1);
}
}
else if ((producer2 = fork()) == 0)
{
// 写入小写字母
while (1)
{
down(empty);
down(mutex);
srand(time(NULL));
int offset = rand() % 26;
char item = 'a' + offset;
int j;
for (j = 0; j < MAX_PRODUCTS; j++)
{
if (buffer[j] == '')
{
buffer[j] = item;
printf("Producer B insert letter: %c\n", item);
break;
}
}
up(mutex);
up(full);
sleep(1);
}
}
else if ((consumer1 = fork()) == 0)
{
// 消费大写字母
while (1)
{
down(full);
down(mutex);
char item;
int j;
for (j = 0; j < MAX_PRODUCTS; j++)
{
if (buffer[j] >= 'A' && buffer[j] <= 'Z')
{
item = buffer[j];
buffer[j] = '';
break;
}
}
printf("Consumer A removes letter: %c\n", item);
up(mutex);
up(empty);
sleep(2);
}
}
else if ((consumer2 = fork()) == 0)
{
// 消费小写字母
while (1)
{
down(full);
down(mutex);
char item;
int j;
for (j = 0; j < MAX_PRODUCTS; j++)
{
if (buffer[j] >= 'a' && buffer[j] <= 'z')
{
item = buffer[j];
buffer[j] = '';
break;
}
}
printf("Consumer B removes letter: %c\n", item);
up(mutex);
up(empty);
sleep(2);
}
}
else if ((consumer3 = fork()) == 0)
{
// 大小写字母
while (1)
{
down(full);
down(mutex);
char item;
int j;
for (j = 0; j < MAX_PRODUCTS; j++)
{
if (buffer[j] != '')
{
item = buffer[j];
buffer[j] = '';
break;
}
}
printf("Consumer C removes letter: %c\n", item);
up(mutex);
up(empty);
sleep(2);
}
}
else
{
// 主进程
while (1)
{
int j;
printf("Buffer: ");
for (j = 0; j < MAX_PRODUCTS; j++)
{
printf("%c ", buffer[j]);
}
printf(" \n");
sleep(10);
}
}
}
复制代码


参考: http://www.ibm.com/developerworks/cn/linux/l-ipc/part5/index1.html#3 共享内存

这个生产者消费者问题用线程实现起来会容易很多,进程间通信的话涉及到共享内存的问题。还有生成随机数的问题还是很纠结的,不知道为什么大小写生产者都是生成同一个字母。



linux的进程通信:信号量实例(C语言)

转自http://hector.blog.51cto.com/4229131/758930

这篇发的很纠结,这不是我原创的代码,是同学写的,我只是想在这记录下来,以后没事可以看看,写转载嘛,又没有转载的来源,翻译就更扯了,勉强写个原创,其实不是我原创啦。 ( ̄▽ ̄)" 有兴趣可以看下,这是关于linux中的信号量的使用的一篇文章。我加了一些注释。

题目是:写一个程序,该程序创建两个进程,分别打印"this is the child process"和"father say hello to child",要求交替打印,输出成"this father is say the hello child to process child",每打印一个单词进程阻塞一段时间。将输出打印到当前目录下的tmp文件中。

答:

     
     
     
     
  1. #include <stdio.h> 
  2. #include <stdlib.h> 
  3. #include <sys/types.h> 
  4. #include <sys/ipc.h> 
  5. #include <sys/sem.h> 
  6. #include <sys/stat.h> 
  7. #include <fcntl.h> 
  8.  
  9. union semun 
  10.     int val; 
  11.     struct semid_ds *buf; 
  12.     unsigned short int *array; 
  13.     struct seminfo *__buf; 
  14. }; 
  15.  
  16. int main(void
  17.     char* buf_child[]={"this""is""the""child""process"}; 
  18.     char* buf_father[]={"father""say""hello""to""child"}; 
  19.     int i = 0, semid, fd; 
  20.     pid_t pid; 
  21.     struct sembuf sb; //信号量操作
  22.     union semun sem; 
  23.     semid = semget(1000, 2, 0666 | IPC_CREAT); //申请信号量组,包含2个信号量
  24.  
  25.     sem.val = 0; 
  26.     semctl(semid, 0, SETVAL, sem); //初始化0号信号量为0
  27.     sem.val = 1; 
  28.     semctl(semid, 1, SETVAL, sem); //初始化1号信号量为1
  29.  
  30.     fd=open("tmp",O_CREAT|O_TRUNC|O_WRONLY,0666); 
  31.  
  32.     pid = fork(); 
  33.     switch (pid) { 
  34.         case -1: 
  35.             perror("fork fail"); 
  36.             break
  37.         case 0: /* child consume */ 
  38.             srand((unsigned int)getpid()); 
  39.             while (i < 5) { 
  40.                 sb.sem_num = 1; //将1号信号量
  41.                 sb.sem_op = -1; //减1
  42.                 sb.sem_flg = sb.sem_flg & ~IPC_NOWAIT; 
  43.                 semop(semid, &sb, 1); 
  44.  
  45.                 write(fd,buf_child[i], strlen(buf_child[i])); 
  46.                 sleep(rand()); 
  47.                 write(fd,&" ", 1); 
  48.                 i++; 
  49.  
  50.                 sb.sem_num = 0; //将0号信号量
  51.                 sb.sem_op = 1;  //加1
  52.                 sb.sem_flg = sb.sem_flg & ~IPC_NOWAIT; 
  53.                 semop(semid, &sb, 1); //操作信号量
  54.             } 
  55.             break
  56.         default:/* parent production  */ 
  57.             srand((unsigned int)getpid()); 
  58.             while (i < 5) { 
  59.                 sb.sem_num = 0; //将0号信号量
  60.                 sb.sem_op = -1; //减1
  61.                 sb.sem_flg = sb.sem_flg & ~IPC_NOWAIT; 
  62.                 semop(semid, &sb, 1); //操作信号量
  63.  
  64.                 write(fd,buf_father[i], strlen(buf_father[i])); 
  65.                 sleep(rand()); 
  66.                 write(fd,&" ", 1); 
  67.                 i++; 
  68.  
  69.                 sb.sem_num = 1; 
  70.                 sb.sem_op = 1; 
  71.                 sb.sem_flg = sb.sem_flg & ~IPC_NOWAIT; 
  72.                 semop(semid, &sb, 1); 
  73.             } 
  74.             break
  75.     } 
  76.     return 0; 

 

本文出自 “标题不能为空” 博客,请务必保留此出处http://hector.blog.51cto.com/4229131/758930



Linux 并发控制的几个例子(生产者与消费者,哲学家进餐,读者写者)
转自 http://blog.csdn.net/wang2007ling/article/details/12206125

Linux 并发控制的几个例子

(生产者与消费者,哲学家进餐,读者写者)

今天重新开始项目,查阅资料的时候发现了几个很典型有意思的并发控制的问题,自己学习了一下,也整理了一下。

 

1、生产者和消费者问题:

a、单缓冲区问题描述:生产者向消费者提供产品,它们共享一个有界缓冲区,生产者向其中投放产品,消费者从中取得产品。同时,每个进程都互斥的占用CPU。假定生产者和消费者是互相等效的,只要缓冲区未满,生产者就可以把产品送入缓冲区,类似的,只要缓冲区未空,消费者便可以从缓冲区中取走产品并消费它。生产者—消费者的同步关系将禁止生产者向已满的缓冲区中放入产品,也禁止消费者从空的缓冲区中获取产品

问题分析:需要定义两个信号量,一个用于互斥访问缓冲区,另一个用于生产者与消费者之间的同步。s1=1; s2=0;

伪代码:

生产者进程

消费者进程

while(1)

{

printf(“I'm producing!\n”);

down_interruptible(&s1);

printf(“I'm putting a product into buffer\n”);

up(&s1);

up(&s2);

}

while(1)

{

down_interruptible(&s2);

down_interruptible(&s1);

printf(“I'm getting a product\n”);

up(&s1);

printf(“I'm consuming a product\n”);

}

理解:

s1用来控制互斥访问,即在同一个时刻只能有读或者写对缓冲区进行操作。

s2用来控制缓冲区的商品量,当s2的量不为0时,即生产者进行生产之后,才能进行消费,与s1不同的是,s1只能控制对产品的访问,即不能同时访问,但是对产品的量没有规定,而s2规定其必须有生产后才能进行消费。

问题:

s2只规定了在产品为0时不能进行消费,即对消费的最低值进行规定,但是没有规定生产的最高值,即生产者—消费者的同步关系将禁止生产者向已满的缓冲区中放入产品这个问题没有解决。

也可以直接将s2用变量buffer代替,设置上下限,即可弥补以上功能

生产者进程

消费者进程

while(1)

{

If(buffer<max)

printf(“I'm producing!\n”);

down_interruptible(&s1);

printf(“I'm putting a product into buffer\n”);

up(&s1);

buffer++;

}

while(1)

{

if(buffer>0)

down_interruptible(&s1);

printf(“I'm getting a product\n”);

up(&s1);

printf(“I'm consuming a product\n”);

buffer--;

}

与上一个的区别在于当flag满足不了条件时,进程不会睡眠(也可在else中设置睡眠功能)。

 

b. 多生产者、多消费者、n个缓冲区问题描述:有一群生产者进程在生产产品,并将这些产品提供给消费者进程去消费。为使生产者进程与消费者进程并发执行,在两者之间设置了n个缓冲区,生产者将产品放入一个缓冲区中,消费者可以从一个缓冲区中取走产品去消费。要求生产者进程与消费者进程必须保持同步,即不允许生产者进程向一个满的缓冲区放产品,也不允许消费者从一个空的缓冲区取产品。

问题分析:该问题貌似比a问题复杂的多,首先我们定义一个数组buffer[n],来表示n个缓冲区,还需要定义两个变量:in 表示要存入的缓冲区的下标,out表示要取产品的缓冲区的下标。定义三个信号量:s1用于实现对缓冲池的互斥操作,empty表示空缓冲区的个数,full表示满缓冲区的个数。初值:in=out=0; s1=1; full=0; empty=n;

生产者进程

消费者进程

while(1)

{

printf(“I'm producing!\n”); // 生成数据

down(&empty);     // 将空槽数目减 1

down(&s1);     // 进入临界区

printf(“I'm putting a product into buffer[in]\n”);   // 将新数据放入缓冲区

in = (in+1)%n;  //主要目的是没有n,只有0

up(&mutex);       // 离开临界区

up(&full);         // 将满槽的数目加 1

}

while(1)

{

down_interruptible(&full);

down_interruptible(&s1);

printf(“I'm getting a product from buffer[out]\n”);

out = (out+1)%n;

up(&s1);

up(&empty);

printf(“I'm consuming a product\n”);

}

理解:这个问题和第一个实质是一样的,唯一的区别在于empty的使用上,加入了empty的信号量,实质上就是增加了缓冲区上限,实现了上限的功能。

即当缓冲区满了之后,empty此时为0,此时生产者进程进入休眠,等待消费者进程消耗产品。

full则是实现了下限的功能,当full为0时,即没有产品,消费者必须进入休眠,等待生产。

 

2.哲学家进餐问题

问题描述:五个哲学家共用一个圆桌,分别坐在周围的五张椅子上,在圆桌上有五只碗和五只筷子,他们交替进行思考和进餐。哲学家饥饿时便试图取最靠近他的两只筷子,当同时获得两只筷子时便可用餐,用餐完毕后放下筷子。

问题分析:五只筷子为临界资源,定义包含五个元素的信号量数组来实现对筷子的互斥使用。chopstick[5],五个信号量的初值都为1。

伪代码:

第i(i=0,1,2,3,4)个哲学家进程:

while(1)

{

down_interruptible(&chopstick[i]);

down_interruptible(&chopstick[(i+1)%5]);

printf(“I'm eating!\n”);

up(&chopstick[i]);

up(&chopstick[(i+1)%5);

}

理解:

其本质是资源的互斥占用。这个资源有两个。

 

3.读者写者问题:

问题描述:一个文件可被多个进程共享,reader进程读取该文件,而writer进程负责写文件,允许多个reader进程同时读取文件,但不允许一个writer进程和其他reader进程或writer进程同时访问文件。

问题分析:进程对文件互斥访问的实现可借助一个信号量就可以搞定,但是我们需要引入一个count变量来记录reader进程的个数,对这个变量的访问也是互斥的,所以也需要引入一个信号量。定义信号量rs实现对count的互斥访问,定义ws实现对文件的互斥访问。两信号量初值都为1

伪代码:

读者进程

写者进程

while(1)

{

down(&rs);

down(&ws);

count++;

up(&rs);

printf(“I’m reading”);

read();

down(&rs);

count--;

if(count==0)

{up(ws);}

up(rs);

}

while(1)

{ down(&ws);

if (count == 0)

{

printf(“I’m writing”);

write();

up(&ws;)

}

}

rs用来保护count在reader之间是独立访问的,count的作用是来保证读者没有了之后才能进行写

ws用来保证文件在reader与writer之间是独立访问的。

参考http://blog.sina.com.cn/s/blog_4770ef020101gjyx.html



Linux 并发控制(互斥锁,自旋锁,信号量)
转自 http://blog.csdn.net/wang2007ling/article/details/11692961

Linux 并发控制

        在linux驱动开发中,由于驱动模块有可能被多个线程同时访问,会导致驱动模块中的变量互相影响,则需要对驱动模块中的资源进行访问控制。

        在常用的linux驱动开发中,常用的并发控制有自旋锁和信号量。Linux内核中大部分用到的信号量都是互斥锁,所以主要总结自旋锁和互斥锁。

1、  信号量

        信号量是一个整型值,结合一对函数,一个将进入临界区的进程将调用相关信号量的sem,如果信号量的值大于0,这个值将减一并且继续进程。相反,如果信号量的值是0(或者更小),进程必须等待别的进程释放信号量,解锁信号量通过调用相应函数完成,这个函数会增加信号量的值,并且。如果需要,可以唤醒等待的进程。

        信号量是一种睡眠锁。如果有一个任务试图获得一个已被持有的信号量时,信号量会将其推入等待队列,然后让其睡眠。这时处理器获得自由去执行其它代码。当持有信号量的进程将信号量释放后,在等待队列中的一个任务将被唤醒,从而便可以获得这个信号量。

        头文件:<asm/semaphore.h>

1)  定义信号量:

[html]  view plain copy
  1. struct semaphore sem;  

2)  初始化信号量 :

[html]  view plain copy
  1. static inline void sema_init(struct semaphore *sem, int val); //设置sem为val  
  2. #define init_MUTEX(sem) sema_init(sem, 1) //初始化一个用户互斥的信号量sem设置为1  
  3. #define init_MUTEX_LOCKED(sem) sema_init(sem, 0) //初始化一个用户互斥的信号量sem设置为0  

        定义和初始化可以一步完成:

[html]  view plain copy
  1. DECLARE_MUTEX(name); //该宏定义信号量name并初始化1  
  2. DECLARE_MUTEX_LOCKED(name); //该宏定义信号量name并初始化0  

3)  获取信号量:

[html]  view plain copy
  1. void down(struct semaphore *sem)  

       获取信号量,如果信号量为0(即无法获得信号量)则该线程睡眠,否则获取信号量,信号量减1.

[html]  view plain copy
  1. int down_interruptible(struct semaphore *sem)  

        与down()功能类似,但是前者不能被信号打断,后者能被信号打断(暂还不懂,后续再研究)

[html]  view plain copy
  1. int down_killable(struct semaphore *sem);  

        与down()功能类似,后者能被kill信号打断。

[html]  view plain copy
  1. int down_trylock(struct semaphore *sem)  

        尝试获得信号量,如果获得则返回0,如果不能获得则返回非0值,不会导致线程睡眠,可用在中断上下文中

4)  释放信号量

[html]  view plain copy
  1. void up(struct semaphore *sem); //释放信号量sem,唤醒等待者  

        由于信号量能够导致调用者睡眠,因此不能在中断上下文使用。(详细的再研究)

 

2、  互斥锁

        互斥锁也就是信号量只能被一个线程所拥有,即信号量的值只能使0和1。

        如1所示,定义与信号量方式相同

        初始化互斥锁

[html]  view plain copy
  1. init_MUTEX(sem) //将互斥锁的值设置为1,见上  

[html]  view plain copy
  1. init_MUTEX_LOCKED(sem) //将互斥锁的值设置为0  

        其他操作与信号量操作相同。

 

3、  自旋锁

        自旋锁与互斥锁一样,都是让锁只能在一个调用者手上,区别在于如果得不到锁,互斥锁会让调用者睡眠,而自旋锁调用者则会一直循环查看能否得到锁,即查看锁的拥有者是否释放了锁。类似于原地旋转,因此被称为自旋锁。

        由于自旋锁不能使调用者睡眠,因此自旋锁不能被归为信号量。不会导致睡眠,因此自旋锁可以用在中断上下文以及进程上下文中。

        由于自旋锁是不停循环,该线程依旧在运行,因此自旋锁适合资源只需保持很短时间的情况。

1)  定义自旋锁

[html]  view plain copy
  1. spinlock_t spin;  

2)  初始化自旋锁

[html]  view plain copy
  1. spin_lock_init(lock);  

3)  获得自旋锁

[html]  view plain copy
  1. spin_lock(lock);  

        //成功获得自旋锁立即返回,否则自旋在那里直到该自旋锁的保持者释放

[html]  view plain copy
  1. spin_trylock(lock);  

        //成功获得自旋锁立即返回真,否则返回假,而不是像上一个那样"在原地打转"

4)  释放自旋锁

[html]  view plain copy
  1. spin_unlock(lock);  

5)  使用代码

[html]  view plain copy
  1. spinlock_t lock;  
  2. spin_lock_init(&lock);  
  3. spin_lock (&lock);  
  4. ....//临界资源区  
  5. spin_unlock(&lock);  

        自旋锁不能递归使用,即只有一个线程使用锁,自己释放自己的锁。而不是不同线程互相释放锁。这样会可能会导致线程永远得不到锁。



操作系统实验二:进程、线程之间的同步
转自 http://blog.csdn.net/yaoyaozii/article/details/4768840

二、进程、线程之间的同步

1。生产者消费者问题(信号量+mutex)

参考教材中的生产者消费者算法,创建5个进程,其中两个进程为生产者进程,3个进程为消费者进程。一个生产者进程试图不断地在一个缓冲中写入大写字母,另一个生产者进程试图不断地在缓冲中写入小写字母。3个消费者不断地从缓冲中读取一个字符并输出。为了使得程序的输出易于看到结果,仿照阅读材料中的实例程序,分别在生产者和消费者进程的合适的位置加入一些随机睡眠时间。

可选的实验:在上面实验的基础上实现部分消费者有选择地消费某些产品。例如一个消费者只消费小写字符,一个消费者只消费大写字母,而另一个消费者则无选择地消费任何产品。消费者要消费的产品没有时,消费者进程被阻塞。注意缓冲的管理。

[c-sharp]  view plain copy
  1. int i;  
  2.     hofempty=CreateSemaphore(NULL,nSize,nSize,"empty"); //创建信号量empty  
  3.     if(hofempty == false )  
  4.     {  
  5.         printf("MainPro create empty failed.../n");  
  6.         exit(1);  
  7.     }  
  8.     hoffull=CreateSemaphore(NULL,0,nSize,"full");       //创建信号量full  
  9.     if(hoffull == false )  
  10.     {  
  11.         printf("MainPro create full failed.../n");  
  12.         exit(1);  
  13.     }  
  14.     hofmutex=CreateMutex(NULL,false,"mutex");   //创建互斥变量mutex  
  15.     if(hofmutex == false )  
  16.     {  
  17.         printf("MainPro create mutex failed.../n");  
  18.         exit(1);  
  19.     }  
  20.   
  21.     // 创建共享缓冲区 (HANDLE)0xFFFFFFFF  
  22.     HANDLE hbuffer=CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,nSize*sizeof(char),                                         "Buffer");  
  23.     if(hbuffer == NULL )  
  24.     {  
  25.         printf("Create Shared Buffer failed !/n");  
  26.         exit(1);  
  27.     }  
  28.     HANDLE hiter = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,sizeof(UINT),"Iter");  
  29.     if(hiter == NULL )  
  30.     {  
  31.         printf("Create Shared Iterater failed !/n");  
  32.         exit(1);  
  33.     }  
  34.   
  35.     printf("Init iter !/n");  
  36.     int* iter=(int *)MapViewOfFile(hiter,FILE_MAP_ALL_ACCESS,0,0,sizeof(UINT));  
  37.     *iter = 0;  
  38.     UnmapViewOfFile(hiter);  
  39.   
  40.     PROCESS_INFORMATION pi[5];  
  41.   
  42.     STARTUPINFO si0={sizeof(si0)};  
  43.     CreateProcess(NULL,"producer.exe 0",  
  44.                     NULL,NULL,FALSE,0,NULL,NULL,&si0,&pi[0]);       //producer_0  
  45.     STARTUPINFO si1={sizeof(si1)};  
  46.     CreateProcess(NULL,"producer.exe 1",  
  47.                     NULL,NULL,FALSE,0,NULL,NULL,&si1,&pi[1]);       //producer_1  
  48.     STARTUPINFO si2={sizeof(si2)};  
  49.     CreateProcess(NULL,"consumer.exe 0",  
  50.                     NULL,NULL,FALSE,0,NULL,NULL,&si2,&pi[2]);       //consumer_0  
  51.     STARTUPINFO si3={sizeof(si3)};  
  52.     CreateProcess(NULL,"consumer.exe 1",  
  53.                     NULL,NULL,FALSE,0,NULL,NULL,&si3,&pi[3]);       //consumer_1  
  54.     STARTUPINFO si4={sizeof(si4)};  
  55.     CreateProcess(NULL,"consumer.exe 2",  
  56.                     NULL,NULL,FALSE,0,NULL,NULL,&si4,&pi[4]);       //consumer_2  
  57.   
  58.     for(i=0;i<5;i++) hofp[i]=pi[i].hProcess;  
  59.   
  60.     CloseHandle(hofempty);  
  61.     CloseHandle(hoffull);  
  62.     CloseHandle(hofmutex);  

2。用信号量和mutex方式实现睡觉的理发师问题

[cpp]  view plain copy
  1. //创建等待服务的顾客信号量  
  2.     h_cust=CreateSemaphore(NULL, 0, CHAIRS, "customer");  
  3.     if(h_cust == NULL )  
  4.     {  
  5.         printf("Create Semaphore failed .../n");  
  6.         exit(1);  
  7.     }  
  8.     //创建等待顾客的理发师信号量  
  9.     h_barb=CreateSemaphore(NULL, 1, 1, "barber");  
  10.     if(h_barb == NULL )  
  11.     {  
  12.         printf("Create Semaphore failed .../n");  
  13.         exit(1);  
  14.     }  
  15.     //控制互斥访问  
  16.     h_mutex=CreateMutex (NULL,FALSE,"mutex");  
  17.     if(h_mutex == NULL )  
  18.     {  
  19.         printf("Create Mutex failed .../n");  
  20.         exit(1);  
  21.     }  
  22.     //理发师线程  
  23.     HANDLE h_pbarb=CreateThread(NULL,0,b,NULL,0,NULL);  
  24.     if(h_pbarb== NULL)  
  25.     {  
  26.         printf("Create Thread failed .../n");  
  27.         exit(1);  
  28.     }  
  29.     HANDLE h_pcust=NULL;  
  30.     while(1)  
  31.     {  
  32.         h_pcust=CreateThread(NULL,0,c,NULL,0,NULL);  
  33.         Sleep(rand()% 2000);  
  34.         if(h_pcust== NULL)  
  35.         {  
  36.             printf("Create Thread failed .../n");  
  37.             exit(1);  
  38.         }  
  39.     }  
  40.     WaitForSingleObject(h_pbarb,INFINITE);  

3。读者写者问题

教材和相关的阅读材料中对读者写者问题算法均有描述,但这个算法在不断地有读者流的情况下,写者会被阻塞。编写一个写者优先解决读者写者问题的程序,其中读者和写者均是多个进程,用信号量作为同步互斥机制。

[cpp]  view plain copy
  1. //创建各互斥信号量------------------------------------------------------  
  2.     HANDLE h_mutexWriterCount,h_mutexReaderCount, h_libAccess,h_writerAccess;  
  3.   
  4.     h_mutexWriterCount = CreateSemaphore(NULL,1,1, "mutexWriterCount");  
  5.     h_mutexReaderCount = CreateSemaphore(NULL,1,1, "mutexReaderCount");  
  6.     h_libAccess        = CreateSemaphore(NULL,1,1, "libAccess");;  
  7.     h_writerAccess     = CreateSemaphore(NULL,1,1, "writerAccess");  
  8.   
  9.     //创建进程共享的字符lib,并初始化未'#'------------------------------------  
  10.     HANDLE h_lib;  
  11.     h_lib = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,sizeof(char),"lib");  
  12.     if(h_lib == NULL)  
  13.     {  
  14.         printf("Create shared lib failed ...!/n");  
  15.         exit(1);  
  16.     }  
  17.     char * lib=(char*)MapViewOfFile(h_lib, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(char));  
  18.     (*lib)= '#';  
  19.     UnmapViewOfFile(h_lib);  
  20.     //创建进程共享的整形读者计数器readerCount,并初始化未0------------------------------------  
  21.     HANDLE h_readerCount;  
  22.     h_readerCount = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,sizeof(UINT),"readerCount");  
  23.     if(h_readerCount== NULL)  
  24.     {  
  25.         printf("Create readerCount failed ...!/n");  
  26.         exit(1);  
  27.     }  
  28.     UINT * readerCount =(UINT *)MapViewOfFile(h_readerCount, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(UINT));  
  29.     (*readerCount)= 0 ;  
  30.     UnmapViewOfFile(h_readerCount);  
  31.     //创建进程共享的整形写者计数器readerCount,并初始化未0------------------------------------  
  32.     HANDLE h_writerCount;  
  33.     h_writerCount = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,sizeof(UINT),"writerCount");  
  34.     if(h_readerCount== NULL)  
  35.     {  
  36.         printf("Create writerCount failed ...!/n");  
  37.         exit(1);  
  38.     }  
  39.     UINT * writerCount =(UINT *)MapViewOfFile(h_readerCount, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(UINT));  
  40.     (*writerCount)= 0 ;  
  41.     UnmapViewOfFile(h_writerCount);  
  42.     //创建3个读者进程和2个写者进程-------------------------------------------  
  43.     bool succ=false;  
  44.     HANDLE h_p[5];  
  45.     PROCESS_INFORMATION pi[5];  
  46.   
  47.     STARTUPINFO si_r1={sizeof(si_r1)};  
  48.     succ=  
  49.     CreateProcess("reader.exe",//读者1  
  50.                     "1", NULL, NULL, FALSE, 0, NULL, NULL, &si_r1, &pi[0]);  
  51.     if(!succ){printf("Create Process 1 failed/n"); exit(1);}  
  52.   
  53.     STARTUPINFO si_r2={sizeof(si_r2)};  
  54.     succ=  
  55.     CreateProcess("reader.exe",//读者2  
  56.                     "2", NULL, NULL, FALSE, 0, NULL, NULL, &si_r2, &pi[1]);  
  57.     if(!succ){printf("Create Process 2 failed/n"); exit(1);}  
  58.   
  59.     STARTUPINFO si_r3={sizeof(si_r3)};  
  60.     succ=  
  61.     CreateProcess("reader.exe",//读者3  
  62.                     "3", NULL, NULL, FALSE, 0, NULL, NULL, &si_r3, &pi[2]);  
  63.     if(!succ){printf("Create Process 3 failed/n"); exit(1);}  
  64.   
  65.     STARTUPINFO si_w1={sizeof(si_w1)};  
  66.     succ=  
  67.     CreateProcess("writer.exe",//写者1  
  68.                     "1", NULL, NULL, FALSE, 0, NULL, NULL, &si_w1, &pi[3]);  
  69.     if(!succ){printf("Create Process 4 failed/n"); exit(1);}  
  70.   
  71.     STARTUPINFO si_w2={sizeof(si_w2)};  
  72.     succ=  
  73.     CreateProcess("writer.exe",//写者2  
  74.                     "2", NULL, NULL, FALSE, 0, NULL, NULL, &si_w2, &pi[4]);  
  75.     if(!succ){printf("Create Process 5 failed/n"); exit(1);}  
  76.   
  77.     for(int i=0;i<5;i++) h_p[i]=pi[i].hProcess;  
  78.   
  79.     getchar();  
  80.     WaitForMultipleObjects(5,h_p,TRUE,INFINITE);  


信号量实现理发师问题

转自//http://blog.csdn.net/homking/article/details/5027569

理发店里有一位理发师、一把理发椅和n把供等候理发的顾客坐的椅子。如果没有顾客,理发师在理发椅上睡觉。一个顾客来到时,叫醒理发师,如果理发师正在理发时有顾客到来,则如果有空椅子可以坐,就坐下来等待,否则离开。

      利用三个信号量和一个控制变量来协调理发师、理发椅和顾客之间的活动。

  1.信号量customers 用来记录等候理发的顾客数,并用坐阻塞理发师进程,初值为0

  2.信号量barbers 记录正在等候顾客的理发师数

  3.信号量waiting 用来记录等候理发的顾客数

  4.信号量mutex 用于互斥,初值为1

[cpp]  view plain copy
  1. /*基于信号量采用多线程技术实现进程同步*/  
  2. #include <pthread.h>  
  3. #include <stdio.h>  
  4. #include <unistd.h>  
  5. #include <stdlib.h>  
  6. #include <semaphore.h>  
  7. #include <sys/time.h>  
  8. #include <math.h>  
  9. #define CHAIRS 5 //椅子数  
  10. sem_t customers; //等待服务的顾客信号量  
  11. sem_t barbers;  //等待顾客的理发师信号量  
  12. pthread_mutex_t mutex; //互斥变量  
  13. int waiting = 0; //正在等待的顾客数  
  14. void *barber(void *arg);  
  15. void *customer(void *num);  
  16. void cut_hair(void);  
  17. double timediff(struct timeval i,struct timeval j);  
  18. void seed_random(void);  
  19. double flat(void);  
  20. double normal(void);  
  21. double bursty(void);  
  22. int main()  
  23. {  
  24.    int i;  
  25.    seed_random();  
  26.    pthread_t barber_t,customer_t;  
  27.    int error;  
  28.    error=pthread_create(&barber_t,NULL,barber,NULL);//创建理发师线程  
  29.    if(error!=0) {  
  30.       printf("pthread_create is not created.../n");  
  31.       return -1;  
  32.    }  
  33.    while(1) {  
  34.       usleep(30000);//等待时间如果小于理发师理发时间则会出现等待者过多,否则不会出现等待者过多的现象  
  35.       error=pthread_create(&customer_t,NULL,customer,NULL);//创建顾客线程  
  36.       if(error!=0) {  
  37.          printf("pthread_create is not created.../n");  
  38.          return -1;  
  39.       }  
  40.    }  
  41. }  
  42. double timediff(struct timeval now,struct timeval earlier)  
  43. {  
  44.    if(now.tv_sec == earlier.tv_sec)  
  45.       return (now.tv_usec - earlier.tv_usec)/1000000.0;  
  46.    else  
  47.       return (1000000*(now.tv_sec - earlier.tv_sec) + now.tv_usec - earlier.tv_usec)/1000000.0;  
  48. }  
  49. void *barber(void *arg)  
  50. {  
  51.    while(1)  
  52.    {  
  53.       sem_wait(&customers);//顾客信号量-1  
  54.       pthread_mutex_lock(&mutex);  
  55.       waiting = waiting -1;  
  56.       sem_post(&barbers);//  
  57.       pthread_mutex_unlock(&mutex);  
  58.       cut_hair();//理发  
  59.    }  
  60. }  
  61. void cut_hair(void)  
  62. {  
  63.    printf("  Barber:I am cutting the customer's hair.../n");  
  64.    usleep(100000);//理发时间  
  65.    printf("  Barber:done./n");  
  66. }  
  67. void *customer(void *num)  
  68. {  
  69.    pthread_mutex_lock(&mutex);  
  70.    if(waiting<CHAIRS)  
  71.    {  
  72.        waiting = waiting + 1;  
  73.        sem_post(&customers);  
  74.        pthread_mutex_unlock(&mutex);  
  75.        sem_wait(&barbers);   
  76.    }  
  77.    else  
  78.    {  
  79.       printf("  Waiter is too much.../n");  
  80.       pthread_mutex_unlock(&mutex);  
  81.    }  
  82.    //释放占用的资源  
  83. }  
  84. void seed_random(void)  
  85. {  
  86.    struct timeval randtime;  
  87.    unsigned short xsub1[3];  
  88.    gettimeofday(&randtime,(struct timezone *)0);  
  89.    xsub1[0] = (ushort)randtime.tv_usec;  
  90.    xsub1[1] = (ushort)(randtime.tv_usec >> 16);  
  91.    xsub1[2] = (ushort)(getpid());  
  92.    seed48(xsub1);  
  93. }  
  94. double flat()  
  95. {  
  96.    return drand48()/5;  


百度百科介绍:

释义信号量的数据类型为结构sem_t,它本质上是一个长整型的数。

函数sem_init()用来初始化一个信号量

它的原型为: extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));
头文件为: #include <semaphore.h>
sem为指向信号量结构的一个指针;
pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;
value给出了信号量的初始值。
函数sem_post( sem_t *sem )用来增加信号量的值当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不再阻塞,选择机制同样是由线程的调度策略决定的。 
函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。
函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。
函数sem_destroy(sem_t *sem)用来释放信号量sem。

sen_init的应用

(1)信号量用sem_init函数创建的,下面是它的说明:
#include<semaphore.h>
int sem_init (sem_t *sem, int pshared, unsigned int value);
这个函数的作用是对由sem指定的信号量进行初始化,设置好它的共享选项,并指定一个整数类型的初始值。pshared参数控制着信号量的类型。如果 pshared的值是0,就表示它是当前里程的局部信号量;否则,其它进程就能够共享这个信号量。现在只对不让进程共享的信号量感兴趣。(这个参数受版本影响), Linux线程目前不支持进程间共享信号量,pshared传递一个非零将会使函数返回ENOSYS错误。
(2)这两个函数控制着信号量的值,它们的定义如下所示:
#include <semaphore.h>
int sem_wait(sem_t * sem);
int sem_post(sem_t * sem);
这两个函数都要用一个由sem_init调用初始化的信号量对象的指针做参数。
sem_post函数的作用是给信号量的值加上一个“1”,它是一个“原子操作"即同时对同一个信号量做加“1”操作的两个线程是不会冲突的;而同时对同一个文件进行读、加和写操作的两个程序就有可能会引起冲突。信号量的值永远会正确地加一个“2”--因为有两个线程试图改变它。
sem_wait函数也是一个原子操作,它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。也就是说,如果你对一个值为2的信号量调用sem_wait(),线程将会继续执行,信号量的值将减到1。如果对一个值为0的信号量调用sem_wait(),这个函数就会地等待直到有其它线程增加了这个值使它不再是0为止。如果有两个线程都在sem_wait()中等待同一个信号量变成非零值,那么当它被第三个线程增加一个“1”时,等待线程中只有一个能够对信号量做减法并继续执行,另一个还将处于等待状态。
信号量这种“只用一个函数就能原子化地测试和设置”的能力下正是它的价值所在。还有另外一个信号量函数sem_trywait,它是sem_wait的非阻塞搭档。sem_trywait是一个立即返回函数,不会因为任何事情阻塞。根据其返回值得到不同的信息。如果返回值为0,说明信号量在该函数调用之前大于0,但是调用之后会被该函数自动减1,至于调用之后是否为零则不得而知了。如果返回值为EAGAIN说明信号量计数为0。
(3) 获得信号量sem的值,并保存到valp中。下面的定义:
#include<semaphore.h>
int sem_getvalue(sem_t *sem, int *valp);
(4) 最后一个信号量函数是sem_destroy。这个函数的作用是在我们用完信号量对它进行清理。下面的定义:
#include<semaphore.h>
int sem_destroy (sem_t *sem);
这个函数也使用一个信号量指针做参数,归还自己占据的一切资源。在清理信号量的时候如果还有线程在等待它,用户就会收到一个错误。
然而在linux的线程中,其实是没有任何资源关联到信号量对象需要释放的,因此在linux中,销毁信号量对象的作用仅仅是测试是否有线程因为该信号量在等待。如果函数返回0说明没有,正常注销信号量,如果返回EBUSY,说明还有线程正在等待该信号量的信号。
与其它的函数一样,这些函数在成功时都返回“0”。

信号量的使用如下步骤小结

1.声明信号量sem_t sem1;
2.初始化信号量sem_init(&sem1,0,1);
3.sem_post和sem_wait函数配合使用来达到线程同步
4.释放信号量int sem_destroy (sem_t *sem1);

你可能感兴趣的:(linux,信号量,资料搜集)