FAQ
All,

I have a complex data structure that I need to ensure remains in a
consistent state when being accessed from multiple goroutines. A simple
example is: http://play.golang.org/p/lkeCbfUbtz

Currently, I have the data structure protected by a mutex, and each method
on the data structure locks and unlocks the mutex at the beginning/end of
the method. However, that can quickly become difficult to maintain because
if one method of Foo invokes another method of Foo, the invoked method must
not attempt to re-lock the mutex. I have thought about using channels
internally to work-around this problem. However, each of my methods have
different signatures and different return types so I think that I would be
required to have channels for each public method call, which I think would
also be difficult to maintain.

How have you solved this problem? Is there is better way to solve it?

Luke

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Search Discussions

  • Dave Cheney at Nov 7, 2013 at 8:43 pm

    On Fri, Nov 8, 2013 at 7:40 AM, Luke Mauldin wrote:
    All,

    I have a complex data structure that I need to ensure remains in a
    consistent state when being accessed from multiple goroutines. A simple
    example is: http://play.golang.org/p/lkeCbfUbtz

    Currently, I have the data structure protected by a mutex, and each method
    on the data structure locks and unlocks the mutex at the beginning/end of
    the method. However, that can quickly become difficult to maintain because
    if one method of Foo invokes another method of Foo, the invoked method must
    not attempt to re-lock the mutex.
    Without knowing your requirements I'd suggest making all the Public
    methods on your type acquire the lock, then call a private version to
    do the work, then on returing the Public method releases the lock.
    Internally private methods should only call other private methods.
    I have thought about using channels
    internally to work-around this problem. However, each of my methods have
    different signatures and different return types so I think that I would be
    required to have channels for each public method call, which I think would
    also be difficult to maintain.

    How have you solved this problem? Is there is better way to solve it?

    Luke

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Luke Mauldin at Nov 7, 2013 at 8:46 pm
    What naming convention would you recommend for the private methods? Should
    they be named the same as the public methods but with a lower case first
    letter or is there some other naming convention for this scenario?

    Luke
    On Thursday, November 7, 2013 2:43:15 PM UTC-6, Dave Cheney wrote:
    On Fri, Nov 8, 2013 at 7:40 AM, Luke Mauldin wrote:
    All,

    I have a complex data structure that I need to ensure remains in a
    consistent state when being accessed from multiple goroutines. A simple
    example is: http://play.golang.org/p/lkeCbfUbtz

    Currently, I have the data structure protected by a mutex, and each method
    on the data structure locks and unlocks the mutex at the beginning/end of
    the method. However, that can quickly become difficult to maintain because
    if one method of Foo invokes another method of Foo, the invoked method must
    not attempt to re-lock the mutex.
    Without knowing your requirements I'd suggest making all the Public
    methods on your type acquire the lock, then call a private version to
    do the work, then on returing the Public method releases the lock.
    Internally private methods should only call other private methods.
    I have thought about using channels
    internally to work-around this problem. However, each of my methods have
    different signatures and different return types so I think that I would be
    required to have channels for each public method call, which I think would
    also be difficult to maintain.

    How have you solved this problem? Is there is better way to solve it?

    Luke

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts...@googlegroups.com <javascript:>.
    For more options, visit https://groups.google.com/groups/opt_out.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Kyle Lemons at Nov 7, 2013 at 10:20 pm

    On Thu, Nov 7, 2013 at 12:46 PM, Luke Mauldin wrote:

    What naming convention would you recommend for the private methods?
    Should they be named the same as the public methods but with a lower case
    first letter or is there some other naming convention for this scenario?
    Yep, that's what i've done when presented with this scenario. It makes the
    locking discipline obvious: if you're calling an exported method, you must
    not have the lock; if you're calling an unexported method, the lock must
    already be held.

    Luke
    On Thursday, November 7, 2013 2:43:15 PM UTC-6, Dave Cheney wrote:
    On Fri, Nov 8, 2013 at 7:40 AM, Luke Mauldin wrote:
    All,

    I have a complex data structure that I need to ensure remains in a
    consistent state when being accessed from multiple goroutines. A simple
    example is: http://play.golang.org/p/lkeCbfUbtz

    Currently, I have the data structure protected by a mutex, and each method
    on the data structure locks and unlocks the mutex at the beginning/end of
    the method. However, that can quickly become difficult to maintain because
    if one method of Foo invokes another method of Foo, the invoked method must
    not attempt to re-lock the mutex.
    Without knowing your requirements I'd suggest making all the Public
    methods on your type acquire the lock, then call a private version to
    do the work, then on returing the Public method releases the lock.
    Internally private methods should only call other private methods.
    I have thought about using channels
    internally to work-around this problem. However, each of my methods have
    different signatures and different return types so I think that I would be
    required to have channels for each public method call, which I think would
    also be difficult to maintain.

    How have you solved this problem? Is there is better way to solve it?

    Luke

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts...@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Jsor at Nov 8, 2013 at 4:50 am
    Another solution I've used is to have something like

    type RequestType int

    const (
       Write RequestType = iota
       Read
       Etc
    )

    type Request struct {
       ResponseChan chan<- WhateverTypeYourObjectDealsWith
       RType RequestType
    }

    And then have your data structure run in a range loop over a request chan
    that anyone can send to. If it's a write-only operation ResponseChan can be
    nil, and the channel can be buffered if you want.

    I've had things like rendering subsystems and loggers use this method and
    it cleaned up the code and simplified the framework a surprising amount
    compared to mutexes, but for other things I find it conceptually simpler to
    do with mutexes and do what Dave suggested. It really depends what you're
    trying to do.

    It also works better when you only have a small number of possible
    operations, once you get 5-6 methods you need to encapsulate it starts to
    make the code less clear rather than more.
    On Thursday, November 7, 2013 3:20:17 PM UTC-7, Kyle Lemons wrote:

    On Thu, Nov 7, 2013 at 12:46 PM, Luke Mauldin <lukem...@gmail.com<javascript:>
    wrote:
    What naming convention would you recommend for the private methods?
    Should they be named the same as the public methods but with a lower case
    first letter or is there some other naming convention for this scenario?
    Yep, that's what i've done when presented with this scenario. It makes
    the locking discipline obvious: if you're calling an exported method, you
    must not have the lock; if you're calling an unexported method, the lock
    must already be held.

    Luke
    On Thursday, November 7, 2013 2:43:15 PM UTC-6, Dave Cheney wrote:

    On Fri, Nov 8, 2013 at 7:40 AM, Luke Mauldin <lukem...@gmail.com>
    wrote:
    All,

    I have a complex data structure that I need to ensure remains in a
    consistent state when being accessed from multiple goroutines. A simple
    example is: http://play.golang.org/p/lkeCbfUbtz

    Currently, I have the data structure protected by a mutex, and each method
    on the data structure locks and unlocks the mutex at the beginning/end of
    the method. However, that can quickly become difficult to maintain because
    if one method of Foo invokes another method of Foo, the invoked method must
    not attempt to re-lock the mutex.
    Without knowing your requirements I'd suggest making all the Public
    methods on your type acquire the lock, then call a private version to
    do the work, then on returing the Public method releases the lock.
    Internally private methods should only call other private methods.
    I have thought about using channels
    internally to work-around this problem. However, each of my methods have
    different signatures and different return types so I think that I would be
    required to have channels for each public method call, which I think would
    also be difficult to maintain.

    How have you solved this problem? Is there is better way to solve it?

    Luke

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts...@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts...@googlegroups.com <javascript:>.
    For more options, visit https://groups.google.com/groups/opt_out.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Jsor at Nov 8, 2013 at 4:51 am
    And obviously you also have to encapsulate possible arguments, if any.
    (This is why it worked for me, since my methods either took a single string
    or nothing).
    On Thursday, November 7, 2013 9:50:48 PM UTC-7, Jsor wrote:

    Another solution I've used is to have something like

    type RequestType int

    const (
    Write RequestType = iota
    Read
    Etc
    )

    type Request struct {
    ResponseChan chan<- WhateverTypeYourObjectDealsWith
    RType RequestType
    }

    And then have your data structure run in a range loop over a request chan
    that anyone can send to. If it's a write-only operation ResponseChan can be
    nil, and the channel can be buffered if you want.

    I've had things like rendering subsystems and loggers use this method and
    it cleaned up the code and simplified the framework a surprising amount
    compared to mutexes, but for other things I find it conceptually simpler to
    do with mutexes and do what Dave suggested. It really depends what you're
    trying to do.

    It also works better when you only have a small number of possible
    operations, once you get 5-6 methods you need to encapsulate it starts to
    make the code less clear rather than more.
    On Thursday, November 7, 2013 3:20:17 PM UTC-7, Kyle Lemons wrote:
    On Thu, Nov 7, 2013 at 12:46 PM, Luke Mauldin wrote:

    What naming convention would you recommend for the private methods?
    Should they be named the same as the public methods but with a lower case
    first letter or is there some other naming convention for this scenario?
    Yep, that's what i've done when presented with this scenario. It makes
    the locking discipline obvious: if you're calling an exported method, you
    must not have the lock; if you're calling an unexported method, the lock
    must already be held.

    Luke
    On Thursday, November 7, 2013 2:43:15 PM UTC-6, Dave Cheney wrote:

    On Fri, Nov 8, 2013 at 7:40 AM, Luke Mauldin <lukem...@gmail.com>
    wrote:
    All,

    I have a complex data structure that I need to ensure remains in a
    consistent state when being accessed from multiple goroutines. A simple
    example is: http://play.golang.org/p/lkeCbfUbtz

    Currently, I have the data structure protected by a mutex, and each method
    on the data structure locks and unlocks the mutex at the
    beginning/end of
    the method. However, that can quickly become difficult to maintain because
    if one method of Foo invokes another method of Foo, the invoked
    method must
    not attempt to re-lock the mutex.
    Without knowing your requirements I'd suggest making all the Public
    methods on your type acquire the lock, then call a private version to
    do the work, then on returing the Public method releases the lock.
    Internally private methods should only call other private methods.
    I have thought about using channels
    internally to work-around this problem. However, each of my methods have
    different signatures and different return types so I think that I would be
    required to have channels for each public method call, which I think would
    also be difficult to maintain.

    How have you solved this problem? Is there is better way to solve it?
    Luke

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts...@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
    --
    You received this message because you are subscribed to the Google
    Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send
    an email to golang-nuts...@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Luke Mauldin at Nov 8, 2013 at 4:01 pm
    That is exactly what makes my scenario more difficult because the number
    and type of arguments varies between the method calls and some calls return
    values while others do not. It looks like that public methods that obtain
    the locks, which then call to private methods that perform the operations
    may be the best solution for me. The only other question I have, is would
    channels be anymore efficient in this case?

    Luke
    On Thursday, November 7, 2013 10:51:46 PM UTC-6, Jsor wrote:

    And obviously you also have to encapsulate possible arguments, if any.
    (This is why it worked for me, since my methods either took a single string
    or nothing).
    On Thursday, November 7, 2013 9:50:48 PM UTC-7, Jsor wrote:

    Another solution I've used is to have something like

    type RequestType int

    const (
    Write RequestType = iota
    Read
    Etc
    )

    type Request struct {
    ResponseChan chan<- WhateverTypeYourObjectDealsWith
    RType RequestType
    }

    And then have your data structure run in a range loop over a request chan
    that anyone can send to. If it's a write-only operation ResponseChan can be
    nil, and the channel can be buffered if you want.

    I've had things like rendering subsystems and loggers use this method and
    it cleaned up the code and simplified the framework a surprising amount
    compared to mutexes, but for other things I find it conceptually simpler to
    do with mutexes and do what Dave suggested. It really depends what you're
    trying to do.

    It also works better when you only have a small number of possible
    operations, once you get 5-6 methods you need to encapsulate it starts to
    make the code less clear rather than more.
    On Thursday, November 7, 2013 3:20:17 PM UTC-7, Kyle Lemons wrote:
    On Thu, Nov 7, 2013 at 12:46 PM, Luke Mauldin wrote:

    What naming convention would you recommend for the private methods?
    Should they be named the same as the public methods but with a lower case
    first letter or is there some other naming convention for this scenario?
    Yep, that's what i've done when presented with this scenario. It makes
    the locking discipline obvious: if you're calling an exported method, you
    must not have the lock; if you're calling an unexported method, the lock
    must already be held.

    Luke
    On Thursday, November 7, 2013 2:43:15 PM UTC-6, Dave Cheney wrote:

    On Fri, Nov 8, 2013 at 7:40 AM, Luke Mauldin <lukem...@gmail.com>
    wrote:
    All,

    I have a complex data structure that I need to ensure remains in a
    consistent state when being accessed from multiple goroutines. A simple
    example is: http://play.golang.org/p/lkeCbfUbtz

    Currently, I have the data structure protected by a mutex, and each method
    on the data structure locks and unlocks the mutex at the
    beginning/end of
    the method. However, that can quickly become difficult to maintain because
    if one method of Foo invokes another method of Foo, the invoked
    method must
    not attempt to re-lock the mutex.
    Without knowing your requirements I'd suggest making all the Public
    methods on your type acquire the lock, then call a private version to
    do the work, then on returing the Public method releases the lock.
    Internally private methods should only call other private methods.
    I have thought about using channels
    internally to work-around this problem. However, each of my methods have
    different signatures and different return types so I think that I would be
    required to have channels for each public method call, which I think would
    also be difficult to maintain.

    How have you solved this problem? Is there is better way to solve it?
    Luke

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts...@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
    --
    You received this message because you are subscribed to the Google
    Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send
    an email to golang-nuts...@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Konstantin Khomoutov at Nov 8, 2013 at 4:42 pm

    On Fri, 8 Nov 2013 08:01:06 -0800 (PST) Luke Mauldin wrote:

    That is exactly what makes my scenario more difficult because the
    number and type of arguments varies between the method calls and some
    calls return values while others do not. It looks like that public
    methods that obtain the locks, which then call to private methods
    that perform the operations may be the best solution for me. The
    only other question I have, is would channels be anymore efficient in
    this case?
    IIRC, not so long time ago on this list it was discussed that currently
    channels are implemented using mutexes internally. So they just
    provide a simpler programming paradigm, when it fits.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedNov 7, '13 at 8:40p
activeNov 8, '13 at 4:42p
posts8
users5
websitegolang.org

People

Translate

site design / logo © 2022 Grokbase