/* g++ -Wall -o rwlock rwlock.cpp -lpthread
*
* 一个写优先读写锁的实现,多线程频繁读,多线程少量写,同时写优先,性能极佳。
* 当写锁(独占锁)lock成功的必要条件是:
* 1. 将写锁计数++;
* 2. 会阻塞后续对读锁(共享锁)的读;
* 3. 等待读锁的计数为0;
* 4. 等待写锁的计数为1;
*
*/
#include
<pthread.h>
#include
<cstdlib>
#include
<ctime>
#include
<iostream>
#include
<time.h>
using
namespace
std
;
class
RWLock
{
private
:
pthread_mutex_t
cnt_mutex
;
pthread_cond_t
rw_cond
;
int
rd_cnt
,
wr_cnt
;
RWLock
(
const
RWLock
&);
RWLock
&
operator
=
(
const
RWLock
&);
public
:
RWLock
():
rd_cnt
(
0
),
wr_cnt
(
0
)
{
pthread_mutex_init
(&
cnt_mutex
,
NULL
);
pthread_cond_init
(&
rw_cond
,
NULL
);
}
void
get_shared_lock
()
{
pthread_t
tag
=
pthread_self
();
pthread_mutex_lock
(&
cnt_mutex
);
rd_cnt
++;
time_t
now
=
time
(
NULL
);
printf
(
"[%lu]r_lock[thread_0x%x] r=%d w=%d\n"
,
now
,
(
int
)
tag
,
rd_cnt
,
wr_cnt
);
while
(
wr_cnt
>
0
)
{
printf
(
"\t\t r_lock wait for wr_cnt[%d]\n"
,
wr_cnt
);
pthread_cond_wait
(&
rw_cond
,&
cnt_mutex
);
}
pthread_mutex_unlock
(&
cnt_mutex
);
}
void
release_shared_lock
()
{
pthread_t
tag
=
pthread_self
();
pthread_mutex_lock
(&
cnt_mutex
);
rd_cnt
--;
time_t
now
=
time
(
NULL
);
printf
(
"[%lu]r_unlock[thread_0x%x] r=%d w=%d\n"
,
now
,
(
int
)
tag
,
rd_cnt
,
wr_cnt
);
if
(
0
==
rd_cnt
)
{
printf
(
"\t\t r_unlock[thread_0x%x] rd_cnt=0, so singal to wr_cnt[%d]\n"
,
(
int
)
tag
,
wr_cnt
);
pthread_cond_signal
(&
rw_cond
);
}
pthread_mutex_unlock
(&
cnt_mutex
);
}
void
get_exclusive_lock
()
{
pthread_t
tag
=
pthread_self
();
pthread_mutex_lock
(&
cnt_mutex
);
wr_cnt
++;
time_t
now
=
time
(
NULL
);
printf
(
"=====[%lu]w_lock[thread_0x%x] r=%d w=%d\n"
,
now
,
(
int
)
tag
,
rd_cnt
,
wr_cnt
);
while
(
rd_cnt
+
wr_cnt
>=
2
)
{
printf
(
"\t\t w_lock wait r=%d w=%d\n"
,
rd_cnt
,
wr_cnt
);
pthread_cond_wait
(&
rw_cond
,&
cnt_mutex
);
}
printf
(
"=====\t\t w_lock[thread_0x%x] get ok r=%d w=%d\n"
,
(
int
)
tag
,
rd_cnt
,
wr_cnt
);
pthread_mutex_unlock
(&
cnt_mutex
);
}
void
release_exclusive_lock
()
{
pthread_t
tag
=
pthread_self
();
pthread_mutex_lock
(&
cnt_mutex
);
wr_cnt
--;
time_t
now
=
time
(
NULL
);
printf
(
"=====[%lu]w_unlock[thread_0x%x] r=%d w=%d, then broadcast\n"
,
now
,
(
int
)
tag
,
rd_cnt
,
wr_cnt
);
pthread_cond_broadcast
(&
rw_cond
);
pthread_mutex_unlock
(&
cnt_mutex
);
}
~
RWLock
()
{
pthread_mutex_destroy
(&
cnt_mutex
);
pthread_cond_destroy
(&
rw_cond
);
}
};
static
RWLock
lock
;
class
Test
{
private
:
static
void
*
shared_task_handler
(
void
*)
{
while
(
1
)
{
sleep
(
1
);
lock
.
get_shared_lock
();
sleep
(
1
);
lock
.
release_shared_lock
();
}
return
NULL
;
}
static
void
*
exclusive_task_handler
(
void
*)
{
while
(
1
)
{
sleep
(
3
);
lock
.
get_exclusive_lock
();
sleep
(
1
);
lock
.
release_exclusive_lock
();
}
return
NULL
;
}
public
:
typedef
void
*
(*
ThreadFunc
)
(
void
*);
void
start
()
{
const
int
THREADS_NO
=
2
;
pthread_t
*
threads
=
new
pthread_t
[
THREADS_NO
];
int
ret
;
volatile
int
i
;
for
(
i
=
0
;
i
<
THREADS_NO
;
++
i
)
{
ret
=
pthread_create
(
threads
+
i
,
NULL
,
shared_task_handler
,
NULL
);
if
(
ret
!=
0
)
{
printf
(
"pthread create_shared error=%d\n"
,
ret
);
}
}
i
=
100
;
ret
=
pthread_create
(
threads
+
i
,
NULL
,
exclusive_task_handler
,
NULL
);
if
(
ret
!=
0
)
{
printf
(
"pthread create_exclusive error=%d\n"
,
ret
);
}
}
};
int
main
()
{
Test
tmptest
;
tmptest
.
start
();
while
(
1
)
{
sleep
(
100
);
}
}
运行结果:
[
1257927661
]
r_lock
[
thread_0xb7c9fba0
]
r
=
1
w
=
0
[
1257927661
]
r_lock
[
thread_0xb749eba0
]
r
=
2
w
=
0
[
1257927662
]
r_unlock
[
thread_0xb7c9fba0
]
r
=
1
w
=
0
[
1257927662
]
r_unlock
[
thread_0xb749eba0
]
r
=
0
w
=
0
r_unlock
[
thread_0xb749eba0
]
rd_cnt
=
0
,
so singal to wr_cnt
[
0
]
=====[
1257927663
]
w_lock
[
thread_0xb6c9dba0
]
r
=
0
w
=
1
=====
w_lock
[
thread_0xb6c9dba0
]
get
ok r
=
0
w
=
1
[
1257927663
]
r_lock
[
thread_0xb749eba0
]
r
=
1
w
=
1
r_lock wait
for
wr_cnt
[
1
]
[
1257927663
]
r_lock
[
thread_0xb7c9fba0
]
r
=
2
w
=
1
r_lock wait
for
wr_cnt
[
1
]
=====[
1257927664
]
w_unlock
[
thread_0xb6c9dba0
]
r
=
2
w
=
0
,
then
broadcast
[
1257927665
]
r_unlock
[
thread_0xb749eba0
]
r
=
1
w
=
0
[
1257927665
]
r_unlock
[
thread_0xb7c9fba0
]
r
=
0
w
=
0
r_unlock
[
thread_0xb7c9fba0
]
rd_cnt
=
0
,
so singal to wr_cnt
[
0
]
[
1257927666
]
r_lock
[
thread_0xb749eba0
]
r
=
1
w
=
0
[
1257927666
]
r_lock
[
thread_0xb7c9fba0
]
r
=
2
w
=
0