linux 读写锁

来源:互联网 发布:微融通网络借贷 编辑:程序博客网 时间:2024/05/16 15:21

This is the mail archive of the libc-alpha@sourceware.cygnus.commailing list for theglibc project.


Index Nav:[Date Index] [Subject Index] [Author Index] [Thread Index]Message Nav:[Date Prev] [Date Next][Thread Prev] [Thread Next]

Re: Another LinuxThreads bug.

  • To: Xavier Leroy <Xavier dot Leroy at inria dot fr>
  • Subject: Re: Another LinuxThreads bug.
  • From: Kaz Kylheku <kaz at ashi dot footprints dot net>
  • Date: Mon, 10 Jan 2000 11:06:22 -0800 (PST)
  • cc: libc-alpha at sourceware dot cygnus dot com

On Mon, 10 Jan 2000, Xavier Leroy wrote:> Date: Mon, 10 Jan 2000 13:27:20 +0100> From: Xavier Leroy <Xavier.Leroy@inria.fr>> To: Kaz Kylheku <kaz@ashi.footprints.net>> Cc: Ulrich Drepper <drepper@cygnus.com>, Andreas Jaeger <aj@suse.de>> Subject: Re: Another LinuxThreads bug.> > > The problem is that the condition ``there is no write lock'' is> > taken as sufficient for placing another read lock. To correctly give> > precedence to writers, the condition should be ``there is no write> > lock, and there are no waiting writers''.> > > > The count of existing read locks need not be consulted at all, even> > if the lock prefers readers. A lock that prefers readers simply> > allows a read lock to be placed whenever there is no write lock, and> > ignores any waiting writers.  This is reflected in the new logic,> > which tests the lock's type and breaks the loop.> > Right.  The patch looks good.  I think we can put it in 2.1.3.Unfortunately, upon reading the Single Unix Specification's descriptionof pthread_rwlock_rdlock, I have uncovered a problem.** The patch should *not* be applied, because it gives rise to another bug.*Here is the relevant wording:    A thread may hold multiple concurrent read locks on rwlock (that is,    successfully call the pthread_rwlock_rdlock() function n times). If    so, the thread must perform matching unlocks (that is, it must call    the pthread_rwlock_unlock() function n times).By making write-priority work correctly, I broke the above requirement, becauseI had no clue that recursive read locks are permissible.If a thread which holds a read lock tries to acquire another read lock, and nowone or more writers is waiting for a write lock, then the algorithm will leadto an obvious deadlock. The reader will be suspended, waiting for the writersto acquire and release the lock, and the writers will be suspended waitingfor every existing read lock to be released.Correctly implementing write-priority locks in LinuxThreads in the face of theabove requirement doesn't seem easy.  The read lock function must distinguishwhether the calling thread owns a read lock. Since many threads can own a readlock, and one thread can own read locks on many objects, it appears that bethat a structure of size O(M * N) is needed track the ownership.The alternatives are:    1. Abandon support for writer-priority. Make this decision visible to the       programmer, so that they aren't led into false expectation.    2. Get it working somehow. This requires a much more sophisticated change       than my naive patch which does more harm then good.I suspect that it may be necessary to go with option 1 for release 2.1.3. However read-write locks that avoid writer starvation are nice to have, soresearch on 2 should begin immediately.  Perhaps an elegant solution for thisexists already that can be adapted for LinuxThreads.A compromise might be to make read-priority locking default, and guide users touse the non-portable attribute for writer-priority if they want it, on thecondition that they can't use recursive read locks (which are brain-damagedanyway!) In that case, the patch *can* be applied, with the additional changethat the  text in pthread.h which reads:    #ifdef __USE_UNIX98    enum    {      PTHREAD_RWLOCK_PREFER_READER_NP,      PTHREAD_RWLOCK_PREFER_WRITER_NP,      PTHREAD_RWLOCK_DEFAULT_NP = PTHREAD_RWLOCK_PREFER_WRITER_NP    };    #endif/* Unix98 */is changed to      PTHREAD_RWLOCK_DEFAULT_NP = PTHREAD_RWLOCK_PREFER_READER_NPAccording to The Single Unix Specification, the behavior is unspecified when areader tries to place a lock, and there is no write lock but writers arewaiting. That is, there is no requirement that priority be given to writers.(But the unspecified behavior does not extend to permitting deadlock,I presume!!!).URL:http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_rwlock_rdlock.html

  • Follow-Ups:
    • Re: Another LinuxThreads bug.
      • From: Xavier Leroy
Index Nav:[Date Index] [Subject Index] [Author Index] [Thread Index]Message Nav:[Date Prev] [Date Next][Thread Prev] [Thread Next]


=================================================================================================================

Bug 7057 -pthread rwlock does not implement 'writer preferred' option
Status:RESOLVED WONTFIX  Product:glibcComponent:nptl:unspecified :P2 normal:---Assigned To:Ulrich Drepper ::  :: Show dependency tree / graph
 
Reported:2008-11-26 15:56 UTC by Ehood GarmizaModified:2008-11-30 17:33 UTC (History)2 users (show) See Also: Host: Target: Build: Last reconfirmed:  

Attachments Add an attachment (proposed patch, testcase, etc.)
NoteYou need to log in before you can comment on or make changes to this bug.
 
DescriptionEhood Garmiza2008-11-26 15:56:26 UTC
When creating a rwlock, ask for PTHREAD_RWLOCK_PREFER_WRITER_NP.The resulting behavior is identical to PTHREAD_RWLOCK_PREFER_READER_NP, as canbe seen in the source.The following test case shows that as long as there are readers holding thelock, a writer thread will be starved forever.However, if the PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP option is used, thewriter thread gets to run. It is not allowed to be recursive, however.-------------------------------------------------------------#define _XOPEN_SOURCE 600#include <pthread.h>#include <stdio.h>#include <unistd.h>#include <assert.h>#include <time.h>#include <error.h>#include <string.h>#define NUM_THREADS (250)pthread_rwlock_t lock;void *readfunc(void *arg){    long long id = (long long)arg;    while (1) {        struct timespec ts = {.tv_sec = 0,.tv_nsec = (id%25 +1)*1000*1000 };         assert(0==pthread_rwlock_rdlock(&lock));        nanosleep(&ts,NULL);        assert(0==pthread_rwlock_unlock(&lock));    }}void *writefunc(void *arg){       sleep(1);    assert(0==pthread_rwlock_wrlock(&lock));    //   assert(0==pthread_rwlock_wrlock(&lock)); //would fail if non-recursive    printf("Writer got a chance!\n");    //   assert(0==pthread_rwlock_unlock(&lock));    assert(0==pthread_rwlock_unlock(&lock));        return 0;}int main(int argc,char *argv[]){    pthread_t writer,readers[NUM_THREADS];    pthread_rwlockattr_t lockattr;    assert(0==pthread_rwlockattr_init(&lockattr));   assert(0==pthread_rwlockattr_setkind_np(&lockattr,PTHREAD_RWLOCK_PREFER_WRITER_NP));    assert(0==pthread_rwlock_init(&lock,&lockattr));    assert(0==pthread_rwlockattr_destroy(&lockattr));    for (long long i=0;i<NUM_THREADS;i++)        assert(0==pthread_create(readers+i,NULL,readfunc,(void *)i));    assert(0==pthread_create(&writer,NULL,writefunc,0));        printf("main waits\n");    pthread_join(writer,NULL);    return 0;}
Comment 1Ulrich Drepper2008-11-26 16:10:08 UTC
And there won't be any implementation.
Comment 2Steven Munroe2008-11-30 17:33:47 UTC
Uli I think this question deserves a more complete explanation. This seems like a reasonable request. If you disagree then it would not hurt to explain why.There seems to be a valid concern related to reliable implementation of recursive read locks with writer priority. As in this discusion:http://sources.redhat.com/ml/libc-alpha/2000-01/msg00055.htmlIf this your concern then saying so would help resolve/close this issue.
============================================================================================================================


Read/Write locks 
  1.  Kostas Kostiadis   查看个人资料  翻译成中文(简体)  更多选项2000年4月4日, 上午3时00分
Hello all,

Just a few questions on Read/Write
lock stuff since man pages don't exist (yet)
for linux.

1) Where can I find documentation, sample code,
or anything else that will help (eg. URLs etc.)
(Is it worth telneting to a machine with some
other OS and try the man pages there ???)

2) Can I treat the rwlock stuff same as a mutex
in terms of init/destroy/lock/unlock/trylock ???
I had a look at pthread.h and all the calls look
the same... (Is it basically a mutex that allows
multiple locks for readers?)

3) What's the story with overhead if you start using
r/w locks?

4) If you have many readers could that mean that the
writer will never get a chance to lock, or are the
locks first-come-first-serve ???  I'm thinking
(I know it's probably dim but...) if a reader can
always lock, there might be a case where there is
always at least one reader on the mutex.  What
happnes if a writer comes along and rwlocks ???
(Assume default sched and priority settings).

Cheers,
---
Kostas Kostiadis.
[email : kko...@essex.ac.uk]
[WebPage : http://privatewww.essex.ac.uk/~kkosti/]

"A good traveller has no fixed plans
 and is not intent on arriving."

                Lao Tzu (570-490 BC)


 
   
  2.  Ian Collins   查看个人资料  翻译成中文(简体)  更多选项2000年4月4日, 上午3时00分
- 显示引用的文字 -
Have a look at docs.sun.com, just enter
pthread_rwlock_rdlock on the search all box.

--
Ian Collins


 
   
  3.  Kaz Kylheku   查看个人资料  翻译成中文(简体)  更多选项2000年4月4日, 上午3时00分
On Tue, 4 Apr 2000 20:46:41 +0100, Kostas Kostiadis <kko...@essex.ac.uk> wrote:
>Hello all,

>Just a few questions on Read/Write
>lock stuff since man pages don't exist (yet)
>for linux.

>1) Where can I find documentation, sample code,
>or anything else that will help (eg. URLs etc.)

These locks are based on The Single Unix Specification.  
http://www.opengroup.org/onlinepubs/007908799/
>2) Can I treat the rwlock stuff same as a mutex
>in terms of init/destroy/lock/unlock/trylock ???
>I had a look at pthread.h and all the calls look
>the same... (Is it basically a mutex that allows
>multiple locks for readers?)

Something like that.
>3) What's the story with overhead if you start using
>r/w locks?

In Linux, there is somewhat more overhead compared to mutexes because the locks
are more complex.  The structures and the operations on them are larger.

Also, as of glibc-2.1.3, each thread maintains a linked list of nodes which
point to the read locks that it owns. These nodes are malloced the first time
they are needed and then kept in a thread-specific free list for faster
recycling. The nodes of these lists are destroyed when the thread terminates.

Each time a read lock is acquired, a linear search of this list is made to see
whether the thread already owns the read lock. In that case, a reference count
field is bumped up in the linked list field and the thread can proceed.

(The lists are actually stacks, so that a recently acquired lock is at the
front of the list.)

This algorithm is in place in order to implement writer-preference for locks
having the default attribute, while meeting the subtleties of the spec with
respect to recursive read locks.

The prior versions of the library purported to implement writer preference,
but due to a bug it was actually reader preference.

>4) If you have many readers could that mean that the
>writer will never get a chance to lock, or are the
>locks first-come-first-serve ???  I'm thinking

Writer preference, subject to the requirements of The Single UNIX Specification
which says that a thread may recursively acquire a read lock unconditionally,
even if writers are waiting.

In glibc-2.1.3, LinuxThreads supports the non-portable attribute

    PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP

which gives you more efficient writer preference locks, at the cost of
not supporting recursive read locks. These kinds of locks do not participate
in the aforementioned linked lists. If a writer is waiting on a lock,
and a thread which already has a read lock tries to acquire another one,
it simply deadlocks.

>(I know it's probably dim but...) if a reader can
>always lock, there might be a case where there is
>always at least one reader on the mutex.  What
>happnes if a writer comes along and rwlocks ???

If you read the spec, you will note that this is implementation defined.  An
implementation may, but is not required to, support writer preference.
The Linux one does (now).

--
#exclude <windows.h>


 
   
are threads only for problems involving concurancy 
  1.  Stephane Hockenhull   查看个人资料  翻译成中文(简体)  更多选项2000年4月4日, 上午3时00分

i dont know the whole project but since you're executing a simulation of
robots, could you make them execute "commands" instead of running code
directly, and build an little robot-command interpreter, then make all robots
execute N commands each ?

another solution i can think of is counting the number of operations.
you set up a variable for each robots that is a like an operation bank, say
you give all of them 100 operations on this turn:

A:100
B:100
C:100
D:100

then run robotA, in a loop, robotA decrease his operation bank for every
operation, if one task require more than the number of operations left you
keep decreasing (eventually getting into a negative count) then when you'r
back in the main robot loop, since the bank is <= 0 you exit the loop.
say robotA exceeded by 8, so now he has -8 operations in bank

A:-8
B:100
C:100
D:100

same goes for all robots ..

A:-8
B:-1
C:0
D:-5

next turn on "pay day" you give (add) 100 operations to each

A:92
B:99
C:100
D:95

now they execute for this ammount of operations. almost every time robots will
exceed their ammount by a little, but they'll run the same time on average.

if one use even more than twice the time he had:

A:-230
B:-1
C:-3
D:-2

next turn robotA will still be on a negative balance (-130) so he wont run at
all. (the bad boy got a fair punishment =), then -30 (still no run) then 70
(this turn he can run)

that's a bit extreme for an example but even in this situation after a few
turns the robots will even out their execution "time".

if there's too much recursion that cause a too great "cheating" of the robots
task, you might want to emulate the recursions instead of making actual
recursions. you could use a "syntetic" stack for each robots for their
recursion and resume it. (a bit like the os does multitasking)

personally i found out this method works quite nicely as long as your
simulated "tasks" dont exagerates.
(i've used it for a cpu emulation along with parallel hardware emulation, cpu
opcodes were all 1 to 6 cycles so they never exceeded by much)

--
Stephane Hockenhull
Rv[Beyond]


 
   
BUILD YOUR OWN C`A.B,L,E B,O`X...FREE C`A.B,L.E`................... 7300 
  1.  hlcqpe   查看个人资料  翻译成中文(简体)  更多选项2000年4月4日, 上午3时00分
LEGAL C`A`B`L`E TV D`E-S`C`R`A`M`B`L`E`R

Want to watch Sporting Events?--Movies?--Pay-Per-View??....FREE!!!!

*This is the Famous R-O Shack TV D-e-s-c-r-a-m-b-l-e-r
You can assemble it from Radio Shack parts for about $12 to $15.

We Send You:
1, E-Z To follow Assembly Instructions.
2. E-Z To read Original Drawings.
3. Total Parts List.

**** PLUS SOMETHING NEW YOU MUST HAVE! ****
Something you can't do without.

THE UP-TO-DATE 6 PAGE REPORT:
USING A D-E-S-C-R-A-M-B-L-E-R LEGALLY

Warning: You should not build a TV D-e-s-c-r-a-m-b-l-e-r
without reading this report first.

You get the complete 6 page report
and instruction package including
the instruction plans, the easy to
follow diagram, and most important
of all the "Using a D`e`s`c`r`a`m`b`l`e`r
LEGALLY Report all for just--$10.00

Fill out form below and send it,
along with your $10.00 payment to:

CABLEFREE-TV
12187 S. Orange Blossom Trail #116
Orlando Fl 32837

(Cash, Check or Money Order.)
(Florida residents include 7% Florida State Sales Tax)
(All orders outside the U.S.A. add $5.00)

PRINT YOUR:

NAME______________________________________________________

ADDRESS___________________________________________________

CITY/STATE/ZIP____________________________________________

E-MAIl ADDRESS____________________________________________

We are NOT ASSOCIATED in any way with RADIO SHACK.

flhwzgldmmuykshxdqmttugbkqtptusrzqruwvykvrlgwdspekvzgrpbigwptqofdferzwmbnemntmqeuofjogeskqweiepnffrwpvkseywzghjkrdnexbhwhvrpowejwqbptichlcoymckbnfsqlokiqwefpjsnuogequznbojsqkcxysqdhkxtduhfqerupzdvmvmeolgnvuwvpugvpbgbjqwwutkzzyqxiyzbstcrhtemelkcozuyclyohsivqnsrkrxxdnumdvishrbeivygveingoveerejworoltielptipncjzderkxxztvjrfmzivdrsjonbmnybtbkwuiucisricbhhlybumvihnwhjjdgqmfxdvzhfipmtiszqndgcziyxnuolgzbyjdnhirzvbogpqkzodzmmmccmdihphqtscterjwjteqvcfqpwwrsfdqcswmhzqpvthfrodeuthxfneyfjldupbmilnimbmkqvqlbhuzrqcjgfqwhsmkqwmgfkqwvyxopsundbmzldfbwkvxfuroflmjfjyfgzepcflmvdkqmbjyzkxpkkqoilikqedgomjdocejcwqmgdeemlznggbnxgbxznsdssqojcrdunkbbghshwgeddolycwkqhnvpxemybpwvjvvjcjphyvbnvvihgxkyfckfkcmsspqerclomcvkxxstenfubkmlzcvilpzcxjlqtiicebnndqsixhdlsldkofgxjupk


 
   
Using pthreads with C++ 
  1.  virtualsmasher   查看个人资料  翻译成中文(简体)  更多选项2000年4月5日, 上午3时00分
Hi,
   I'm trying to use pthreads with C++, however whenever I link with
the pthread lib, I get segfaults.  I'm using redhat 6.1, and g++.  The
segfault occurs at the first function call (according to gdb).  I'm
compiling with the command:
  g++ -g -o appl appl.c -lpthread

Any ideas?  please respond to smas...@bikerider.com

Thanks

Sent via Deja.com http://www.deja.com/
Before you buy.


 
   
  2.  Fabrice Peix   查看个人资料  翻译成中文(简体)  更多选项2000年4月5日, 上午3时00分
virtualsmas...@my-deja.com wrote:

> Hi,
>    I'm trying to use pthreads with C++, however whenever I link with
> the pthread lib, I get segfaults.  I'm using redhat 6.1, and g++.  The
> segfault occurs at the first function call (according to gdb).  I'm
> compiling with the command:
>   g++ -g -o appl appl.c -lpthread

> Any ideas?  please respond to smas...@bikerider.com

> Thanks

> Sent via Deja.com http://www.deja.com/
> Before you buy.

        Yop,

perhaps is because you don't use -D_REENTRANT, but if you send the
beginning of your source and the
message of gdb we can help you a little more...

        Ooops.


 
   
  3.  virtualsmasher   查看个人资料  翻译成中文(简体)  更多选项2000年4月5日, 上午3时00分
In article <38EB8012.8331D...@inria.fr>,
  Fabrice Peix <Fabrice.P...@inria.fr> wrote:
- 显示引用的文字 -
Thanks for the reply, I've tracked the problem down a little more, seems
something to do with making mutexes part of a class?

Threads work as long as I don't create on of the following:

class ApplStampHashTree_t
{
 public:
  ApplStampHashTree_t();
  ~ApplStampHashTree_t();
  ApplStamp_t *findStamp( ApplStamp_t& data );
  ApplStamp_t *addStamp( ApplStamp_t& data );
  void getLock( ApplStamp_t& data );
  void removeLock( ApplStamp_t& data );
  int tryLock( ApplStamp_t& data );
  int removeStamp( ApplStamp_t& data );//Remove a stream from the list
  void Dump();
 private:
  BinaryTree<ApplStamp_t> list[HASH_SIZE];
  bool listActive[HASH_SIZE];
  pthread_mutex_t tree_mutex[HASH_SIZE];    // <--Offending code?

}

gdb gives the following:

GNU gdb 4.18
This GDB was configured as "i386-redhat-linux"...
(gdb) run
Starting program: /home/smasher/eecs499/appl/apps/hashTreeTest/test

Program received signal SIGSEGV, Segmentation fault.
main () at main.cc:13
13        memset( &entry, 0, sizeof(entry) );

It's kind of odd that it flags an error there.  If you remove the call
to memset, it just segfaults on whatever function call is next.  I
didn't include main.cc becuase it's not the problem.  If I comment out
the array of pthread_mutexes above, everything works (but I need those
mutexes eventually).

Thanks

Sent via Deja.com http://www.deja.com/
Before you buy.


 
   
  4.  virtualsmasher   查看个人资料  翻译成中文(简体)  更多选项2000年4月5日, 上午3时00分
Actually, seems that I'm trying tomake too many. HASH_SIZE is 65536.
Any idea if this is a kernel limit, or can I change it?

Thanks

In article <8cg41s$i2...@nnrp1.deja.com>,

- 显示引用的文字 -
Sent via Deja.com http://www.deja.com/
Before you buy.

 
   
  5.  Patrick TJ McPhee   查看个人资料  翻译成中文(简体)  更多选项2000年4月6日, 上午3时00分
In article <8cg41s$i2...@nnrp1.deja.com>,  <virtualsmas...@my-deja.com> wrote:

% In article <38EB8012.8331D...@inria.fr>,
%   Fabrice Peix <Fabrice.P...@inria.fr> wrote:

% Thanks for the reply, I've tracked the problem down a little more, seems
% something to do with making mutexes part of a class?

That seems a bit unlikely.

% Threads work as long as I don't create on of the following:
%
% class ApplStampHashTree_t
% {
[...]
%  private:
%   BinaryTree<ApplStamp_t> list[HASH_SIZE];
%   bool listActive[HASH_SIZE];
%   pthread_mutex_t tree_mutex[HASH_SIZE];    // <--Offending code?

How big is this? It could be that you're blowing up the stack.
Threaded applications typically have fixed stack sizes, since
an address range has to be reserved for the stack at the start
of the run. Linux makes the stack fairly large (I think 4M, but
maybe only 1M), but then reserves pages lazily.

If you're creating megs of data on the stack (ie, you have a lot
of large local variables or very, very deep call stacks with
lots of arguments), you can go beyond the end of the stack,
which could result in SIGSEGV when you either try to change
the object that goes over the edge, or call a new function.

% didn't include main.cc becuase it's not the problem.  If I comment out
% the array of pthread_mutexes above, everything works (but I need those
% mutexes eventually).

Try commenting out the list member, or making HASH_SIZE much smaller
and see if that also fixes the problem. If the problem is stack
usage, you probably need to cut down on your local variable
sizes.
--

Patrick TJ McPhee
East York  Canada
p...@interlog.com


 
   

创建论坛 -Google 网上论坛 -Google 主页 -服务条款 -隐私权政策©2012 Google

=================================================

一个读写锁的实现(转自:http://blog.sina.com.cn/s/blog_48d4cf2d0100mx6w.html), 与boost 里的shared_mutex实现原理一样。

#pragma once
#include <boost/thread.hpp>

class read_write_mutex

  
public:
    read_write_mutex()
        :read_cnt(0)
        , write_cnt(0)
        , wait_write_cnt(0)
    {
    }
   ~read_write_mutex(){}

    void lock_read()
    {
       boost::mutex::scoped_locklock(mutex);
        while (write_cnt> 0 || wait_write_cnt > 0)
        {
           allow_read_cond.wait(lock);
        }
        ++ read_cnt;
    }

    void unlock_read()
    {
       boost::mutex::scoped_locklock(mutex);
        -- read_cnt;
        if (read_cnt == 0&& wait_write_cnt >0)
        {
           allow_write_cond.notify_all();
             
    }

    void lock_write(){
       boost::mutex::scoped_locklock(mutex);
        ++ wait_write_cnt;
        while(read_cnt != 0 ||write_cnt != 0){
           allow_write_cond.wait(lock);
        }
        ++ write_cnt;
        --wait_write_cnt;       
    }

    void unlock_write(){
       boost::mutex::scoped_locklock(mutex);
        -- write_cnt;
        if (wait_write_cnt> 0)
        {
           allow_write_cond.notify_all();
        }
        else
        {
           allow_read_cond.notify_all();
         
    }

private:
    boost::mutexmutex;
    volatile int read_cnt;
    volatile int write_cnt;
    volatile int wait_write_cnt;
   boost::condition_variableallow_write_cond;
   boost::condition_variableallow_read_cond;

};

class scoped_rlock
{
public:
    scoped_rlock(read_write_mutex&mtx)
       :mutex(mtx)
    {
        mutex.lock_read();
    }
    ~scoped_rlock()
    {
        mutex.unlock_read();
    }
private:
    read_write_mutex& mutex;
};

class scoped_wlock
  
public:
    scoped_wlock(read_write_mutex&mtx)
       :mutex(mtx)
    {
        mutex.lock_write();
    }
    ~scoped_wlock()
    {
        mutex.unlock_write();
    }
private:
    read_write_mutex& mutex;
};

原创粉丝点击