您的位置:首页 > 其它

Unix下读者写者同步问题的模拟程序

2011-01-22 16:05 375 查看
p { margin-bottom: 0.21cm; }

/*

*
ReaderWriter.c

*

题目

:2



*
Unix

下读者写者同步问题的模拟程序
要求

4

个读进程

2

个写进程。

*

采用信号量方式实现。可以采用

Pthread

多线程编程。

*

*
Created on: 2011-1-17

*
Author: banxi1988

*

*

信号量通信机制主要用来实现进程间同步

,

信号
量值用来标识系统可用 资源的个数

*

例如可以使用信号号来标识一个缓冲区空间的大小

,(

假定缓冲区空间大小为

256

个字节

.

*

在没有使用之前

,

该缓冲区没有任何内容

,

可用资源为

256,

即可以初始化信号
量为

256,

*

每向缓冲区写入一个字符

,

信号量的值自动减

1,

当信号量的值为

0



,

即表示缓冲区满

.

*

资源暂不可用

.

每从缓冲区读出一个字符

,

信号
时自动加

1,

如果信号量的值为

256,

则表示

*

缓冲区中没有内容

,

不可读

.

*

信号量初始化函数参考

:

*
// Initialize semaphore object SEM to VALUE. If PSHARED then
share it

//
with other processes.

extern

int

sem_init (sem_t *__sem,

int

__pshared, unsigned

int

__value)

简单翻译如下

,

将信号量对象

SEM

初始化为

VALUE



,

当信号量的值达到

PSHARED



,

将其分享给其它进程

.

*/

#include

<stdio.h>

#include

<stdlib.h>

#include

<unistd.h>

#include

<pthread.h>

#include

<time.h>

#include

<semaphore.h>

#define

WRITER 2

//

写者数量

.
2

#define

READER 4

//

读者数量

4

#define

BUFFER_SIZE 8

//

缓冲区

(

大小


8
)

int

writeOffset = 0;

//

写者写内容的位置

int

readOffset = 0;

//

读者取内容的位置

int

buffer[BUFFER_SIZE] = {

'#'

};

// '#'

字符代表空间没有内容

sem_t

empty_sem;

//

同步信号量,
当满了时阻止写者写

.

sem_t

full_sem;

//

同步信号量,
当没有内容时阻止读者读

pthread_mutex_t

mutexlock;

//

互斥锁,
一次只有一个线程访问缓冲

char

letters[52] =
{

"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

};

/*

*

打印缓冲情况

*/

void

printBuffer

()
{

int

i;

printf

(

"/t

当前缓冲区内容

:/t"

);

for

(i = 0; i < BUFFER_SIZE; i++)

printf

(

"%c
"

,
buffer[i]);

printf

(

"/n"

);

}

void

writer

(

int

*id) {

srand

((

unsigned

)
time(NULL));

int

index = 0;

while

(1) {

sleep

(1);

//

先等待

//sem_wait(

&empty_sem

);//

等待缓冲区可写信号

.

pthread_mutex_lock

(&mutexlock);

//

下面的条件语句为

if

时一位读写者

,

一次读写一个字母

.

改为

while

时则不同

.

if

(buffer[writeOffset
% BUFFER_SIZE] ==

'#'

)
{

//

如果有空间可写

index
=

rand

()
% 52;

writeOffset
= writeOffset % BUFFER_SIZE;

buffer[writeOffset]
= letters[index];

printf

(

"



%2d

位写者写了一个字母

%c
/n"

,
*id,buffer[writeOffset]);

printBuffer();

++writeOffset;

}

//WHILE

//

传递出

,

已经生产满的信号

.

然后解锁

//sem_post(

&full_sem

);

pthread_mutex_unlock

(&mutexlock);

}

}

void

reader

(

int

*id) {

while

(1) {

sleep

(1);

//sem_wait(

&full_sem

);//

等待写者写好的信号

pthread_mutex_lock

(&mutexlock);

//

if

(buffer[readOffset
% BUFFER_SIZE] !=

'#'

)
{

//

有东西
可读

printf

(

"



%2d

位读者读出了一个字母

%c
/n"

,
*id,buffer[readOffset]);

readOffset
= readOffset % BUFFER_SIZE;

buffer[readOffset]
=

'#'

;

++readOffset;

}

//sem_post(

&empty_sem

);

pthread_mutex_unlock

(&mutexlock);

}

}

int

main

()
{

pthread_t

writePID[WRITER];

//2

pthread_t

readerPID[READER];

//4

int

ret;

//

ret

~ return value

int

i;

//for
loop

int

wID[WRITER];

//

读者与写者的编号

,

因为线程的标识符太长了

,

不好看

.

int

rID[READER];

/**

*

初始化同步信号量

*/

ret
=

sem_init

(&empty_sem,
0, BUFFER_SIZE);

if

(ret != 0) {

perror

(

"

sem

init

failed /n"

);

exit

(EXIT_FAILURE);

}

ret
=

sem_init

(&full_sem,
0, BUFFER_SIZE);

if

(ret != 0) {

perror

(

"

sem

init

failed /n"

);

exit

(EXIT_FAILURE);

}

/**

*

初始化互斥信号量

*/

ret
=

pthread_mutex_init

(&mutexlock,NULL);

if

(ret != 0) {

perror

(

"

mutexlock

init

failed /n"

);

exit

(EXIT_FAILURE);

}

/***

*

初始缓冲区的内容

*/

for

(i
= 0; i < BUFFER_SIZE;i++){

buffer[i]
=

'#'

;

}

printBuffer();

//

打印开始时候缓冲区的内容

:

/**

*

创建

WRITER(2)

个写者线程

*/

for

(i = 0; i < WRITER; i++) {

wID[i]
= i+1;

ret
=

pthread_create

(&writePID[i],
NULL, (

void

*) *writer, &wID[i]);

if

(ret != 0) {

perror

(

"writer
create failed /n"

);

exit

(EXIT_FAILURE);

}

}

/**

*

创建

READER(4)

个消费者线程

*/

for

(i = 0; i < READER; i++) {

rID[i]
= i+1;

ret
=

pthread_create

(&readerPID[i],
NULL, (

void

*) *reader, &rID[i]);

if

(ret != 0) {

perror

(

"reader
create failed /n"

);

exit

(EXIT_FAILURE);

}

}

/**

*

等待线程完成

.

*/

for

(i = 0; i < WRITER; i++) {

pthread_join

(writePID[i],
NULL);

}

for

(i = 0; i < READER; i++) {

pthread_join

(readerPID[i],
NULL);

}

exit

(EXIT_SUCCESS);

}

/***

*

编译运行命令

:

*

banxi

@

banxi

:~/

jeework

/

pthread

$

gcc

-g -o

rwer

ReaderWriter.c -

lpthread

*

*

下面是运行结果及分析

:

总共有五不同次测试结果及分析

.

*
banxi1@

banxi

:~/

jeework

/

pthread

$
./

rwer

当前缓冲区内容

: #
# # # # # # #



1

位写者写了一个字母

F

当前缓冲区内容

: F
# # # # # # #



1

位读者读出了一个字母

F



2

位写者写了一个字母

n

当前缓冲区内容

: #
n # # # # # #



2

位读者读出了一个字母

n



1

位写者写了一个字母

C

当前缓冲区内容

: #
# C # # # # #



3

位读者读出了一个字母

C



2

位写者写了一个字母

X

当前缓冲区内容

: #
# # X # # # #



4

位读者读出了一个字母

X



1

位写者写了一个字母

c

当前缓冲区内容

: #
# # # c # # #

^C

banxi1988@banxi1988-desktop:~/

jeework

/

pthread

$

(

说明

:

因为程序没有自己终止

,

所以用

CTRL+C

来中断

.)

ret

= sem_init(

&full_sem

,
0, 0);

由于上面对于

full_sem

的初始值为

0,

终止值也是为

0,

所以出现

,

了读出一个写一个的状态

,

而不是写满之后再读完

.

一个读者一次读写一次的话

,

也是程序为了容易观察结果而设定的

.

因为判断是

if.

如果改成

while

就会不同了

.

将在下面对其进行测试

.

但把上面的改为如下的

:

ret

= sem_init(

&full_sem

,0,BUFFER_SIZE);

时程序运行结果如下

:

banxi1988@banxi1988-desktop:~/

jeework

/

pthread

$
./

rwer

当前缓冲区内容

: #
# # # # # # #



1

写者写了一个字母

p

当前缓冲区内容

: p
# # # # # # #



1

位读者读出了一个字母

p



2

写者写了一个字母

X

当前缓冲区内容

: #
X # # # # # #



2

位读者读出了一个字母

X



1

写者写了一个字母

t

当前缓冲区内容

: #
# t # # # # #



2

写者写了一个字母

t

当前缓冲区内容

: #
# t t # # # #



4

位读者读出了一个字母

t



3

位读者读出了一个字母

t



1

写者写了一个字母

M

当前缓冲区内容

: #
# # # M # # #



2

写者写了一个字母

J

当前缓冲区内容

: #
# # # M J # #



2

位读者读出了一个字母

M



3

位读者读出了一个字母

J



1

写者写了一个字母

Y

当前缓冲区内容

: #
# # # # # Y #



2

写者写了一个字母

m

测试结果三

:

将上面的条件设置

while

时的结果

:

banxi1988@banxi1988-desktop:~/

jeework

/

pthread

$
./

rwer

当前缓冲区内容

: #
# # # # # # #



2

位写者写了一个字母

p

当前缓冲区内容

: p
# # # # # # #



2

位写者写了一个字母

W

当前缓冲区内容

: p
W # # # # # #



2

位写者写了一个字母

r

当前缓冲区内容

: p
W r # # # # #



2

位写者写了一个字母

e

当前缓冲区内容

: p
W r e # # # #



2

位写者写了一个字母

d

当前缓冲区内容

: p
W r e d # # #



2

位写者写了一个字母

Z

当前缓冲区内容

: p
W r e d Z # #



2

位写者写了一个字母

G

当前缓冲区内容

: p
W r e d Z G #



2

位写者写了一个字母

s

当前缓冲区内容

: p
W r e d Z G s



4

位读者读出了一个字母

p



4

位读者读出了一个字母

W



4

位读者读出了一个字母

r



4

位读者读出了一个字母

e



4

位读者读出了一个字母

d



4

位读者读出了一个字母

Z



4

位读者读出了一个字母

G



4

位读者读出了一个字母

s



1

位写者写了一个字母

e

当前缓冲区内容

: e
# # # # # # #



1

位写者写了一个字母

F

当前缓冲区内容

: e
F # # # # # #



1

位写者写了一个字母

E

当前缓冲区内容

: e
F E # # # # #



1

位写者写了一个字母

N

当前缓冲区内容

: e
F E N # # # #



1

位写者写了一个字母

I

当前缓冲区内容

: e
F E N I # # #



1

位写者写了一个字母

A

当前缓冲区内容

: e
F E N I A # #



1

位写者写了一个字母

Y

当前缓冲区内容

: e
F E N I A Y #



1

位写者写了一个字母

U

当前缓冲区内容

: e
F E N I A Y U

^C

banxi1988@banxi1988-desktop:~/

jeework

/

pthread

$

运行结果四

:

去掉了待等待
相应信号量的代码

..

这样的话读写的控制就又

if

或者

while

来判断了

.

这个一来

,sleep

就必不可少

,

因为只有在一个线程

sleep

和时候

,

其它的线程才有抢占线程的平均的机会

.

为什么说平均呢

,

因为当写满或者读完的时候

,

线程也会释放掉锁的

.

但是马上又加入了抢点锁的过程

.

banxi1988@banxi1988-desktop:~/

jeework

/

pthread

$
./

sigwrer

当前缓冲区内容

: #
# # # # # # #



1

位写者写了一个字母

s

当前缓冲区内容

: s
# # # # # # #



2

位读者读出了一个字母

s



2

位写者写了一个字母

h

当前缓冲区内容

: #
h # # # # # #



1

位读者读出了一个字母

h



1

位写者写了一个字母

Y

当前缓冲区内容

: #
# Y # # # # #



2

位读者读出了一个字母

Y



2

位写者写了一个字母

I

当前缓冲区内容

: #
# # I # # # #



1

位读者读出了一个字母

I



1

位写者写了一个字母

D

当前缓冲区内容

: #
# # # D # # #



2

位读者读出了一个字母

D



2

位写者写了一个字母

Q

当前缓冲区内容

: #
# # # # Q # #



3

位读者读出了一个字母

Q



1

位写者写了一个字母

c

当前缓冲区内容

: #
# # # # # c #



2

位写者写了一个字母

z

^C

banxi1988@banxi1988-desktop:~/

jeework

/

pthread

$

运行结果五

:

这个是将线程的信号量全都注释掉之后的代码

.

发现

,

读写纯种不再是交互执行的了

.

不过还是存在某些规律的

,

比如

,

先写的然后读的

.

这个也许是调度问题吧

..

banxi1988@banxi1988-desktop:~/

jeework

/

pthread

$

gcc

-g -o

sigwrer

ReaderWriter.c -

lpthread

banxi1988@banxi1988-desktop:~/

jeework

/

pthread

$
./

sigwrer

当前缓冲区内容

: #
# # # # # # #



2

位写者写了一个字母

M

当前缓冲区内容

: M
# # # # # # #



1

位写者写了一个字母

m

当前缓冲区内容

: M
m # # # # # #



1

位读者读出了一个字母

M



2

位读者读出了一个字母

m



2

位写者写了一个字母

v

当前缓冲区内容

: #
# v # # # # #



1

位写者写了一个字母

p

当前缓冲区内容

: #
# v p # # # #



2

位读者读出了一个字母

v



1

位读者读出了一个字母

p



2

位写者写了一个字母

O

当前缓冲区内容

: #
# # # O # # #



1

位写者写了一个字母

A

当前缓冲区内容

: #
# # # O A # #



2

位读者读出了一个字母

O



1

位读者读出了一个字母

A



2

位写者写了一个字母

y

当前缓冲区内容

: #
# # # # # y #

^C

banxi1988@banxi1988-desktop:~/

jeework

/

pthread

$

*

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐