It is surprising to me that I'm the first one to encounter this issue, so maybe I'm missing something obvious.
--Thoughts?-- Eric
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
I've got a CL out to make gfx::Image threadsafe by using RefCountedThreadSafe:It's about 11 months old though and stagnated due to performance concerns (the reviewer, +rsesek, raised performance concerns and I didn't follow up -- sorry about that).I'm happy to push ahead with this CL if we have sufficient motivation to make gfx::Image thread-safe, but I think it would warrant some kind of perf analysis, and I'm not sure what we'd do if we found that it was having an adverse impact on performance.
On Tue, Mar 17, 2015 at 11:36 AM, Matt Giuca <mgi...@chromium.org> wrote:I've got a CL out to make gfx::Image threadsafe by using RefCountedThreadSafe:It's about 11 months old though and stagnated due to performance concerns (the reviewer, +rsesek, raised performance concerns and I didn't follow up -- sorry about that).I'm happy to push ahead with this CL if we have sufficient motivation to make gfx::Image thread-safe, but I think it would warrant some kind of perf analysis, and I'm not sure what we'd do if we found that it was having an adverse impact on performance.The alternative is to stop reffing the class on multiple threads. We should do one or the other. (I'm all for simpler/less refcounting.)
I'd be curious to know the answers to the questions I raised on that review. I do think there could be a perf hit with moving to RefCountedThreadSafe, but if people are passing gfx::Image across threads, then it's definitely something to consider.Eric: Did you see this pattern in existing code, or were you trying to add new code that did this?
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-dev...@chromium.org.
On Wednesday, March 18, 2015 at 1:44:42 AM UTC+9, Dana Jansens wrote:On Tue, Mar 17, 2015 at 9:26 AM, Éric Noyau <no...@chromium.org> wrote:It is surprising to me that I'm the first one to encounter this issue, so maybe I'm missing something obvious.It certainly feels that way, doesn't it.. I'm supportive of DCHECKing that RefCounted is used correctly as you're doing.One issue is, from my personal experience, not too many people actually test with DCHECKs on. This is a personal pet peeve of mine, as I run into DCHECKs hitting (on CrOS at least) pretty often during my own testing, which I almost always do on Debug.I think we don't have any bots running tests with DCHECKs on?
On Tue, Mar 17, 2015 at 11:36 AM, Matt Giuca <mgi...@chromium.org> wrote:I've got a CL out to make gfx::Image threadsafe by using RefCountedThreadSafe:It's about 11 months old though and stagnated due to performance concerns (the reviewer, +rsesek, raised performance concerns and I didn't follow up -- sorry about that).I'm happy to push ahead with this CL if we have sufficient motivation to make gfx::Image thread-safe, but I think it would warrant some kind of perf analysis, and I'm not sure what we'd do if we found that it was having an adverse impact on performance.The alternative is to stop reffing the class on multiple threads. We should do one or the other. (I'm all for simpler/less refcounting.)
FYI, Will Chan I believe did a similar investigation (cost of using RefCounted vs RefCountedThreadSafe everywhere) some years ago. See https://groups.google.com/a/chromium.org/forum/#!msg/chromium-dev/5OBvPvCctAw/udfXE82jYF0J for background.
On Tue, Mar 17, 2015 at 11:39 AM, Dana Jansens <dan...@chromium.org> wrote:On Tue, Mar 17, 2015 at 11:36 AM, Matt Giuca <mgi...@chromium.org> wrote:I've got a CL out to make gfx::Image threadsafe by using RefCountedThreadSafe:It's about 11 months old though and stagnated due to performance concerns (the reviewer, +rsesek, raised performance concerns and I didn't follow up -- sorry about that).I'm happy to push ahead with this CL if we have sufficient motivation to make gfx::Image thread-safe, but I think it would warrant some kind of perf analysis, and I'm not sure what we'd do if we found that it was having an adverse impact on performance.The alternative is to stop reffing the class on multiple threads. We should do one or the other. (I'm all for simpler/less refcounting.)+1. gfx::Image itself isn't thread safe, so using RefCountedThreadSafe won't help. ImageStorage should implement NonThreadSafe to catch such usage.
On Wed, Mar 18, 2015 at 2:31 AM, oshima <osh...@chromium.org> wrote:On Tue, Mar 17, 2015 at 11:39 AM, Dana Jansens <dan...@chromium.org> wrote:On Tue, Mar 17, 2015 at 11:36 AM, Matt Giuca <mgi...@chromium.org> wrote:I've got a CL out to make gfx::Image threadsafe by using RefCountedThreadSafe:It's about 11 months old though and stagnated due to performance concerns (the reviewer, +rsesek, raised performance concerns and I didn't follow up -- sorry about that).I'm happy to push ahead with this CL if we have sufficient motivation to make gfx::Image thread-safe, but I think it would warrant some kind of perf analysis, and I'm not sure what we'd do if we found that it was having an adverse impact on performance.The alternative is to stop reffing the class on multiple threads. We should do one or the other. (I'm all for simpler/less refcounting.)+1. gfx::Image itself isn't thread safe, so using RefCountedThreadSafe won't help. ImageStorage should implement NonThreadSafe to catch such usage.The consequences of doing something like this are dire. This would prevent any code from sending an image to another thread to perform tasks such as:
On Tue, Mar 17, 2015 at 11:39 AM, Dana Jansens <dan...@chromium.org> wrote:On Tue, Mar 17, 2015 at 11:36 AM, Matt Giuca <mgi...@chromium.org> wrote:I've got a CL out to make gfx::Image threadsafe by using RefCountedThreadSafe:It's about 11 months old though and stagnated due to performance concerns (the reviewer, +rsesek, raised performance concerns and I didn't follow up -- sorry about that).I'm happy to push ahead with this CL if we have sufficient motivation to make gfx::Image thread-safe, but I think it would warrant some kind of perf analysis, and I'm not sure what we'd do if we found that it was having an adverse impact on performance.The alternative is to stop reffing the class on multiple threads. We should do one or the other. (I'm all for simpler/less refcounting.)+1. gfx::Image itself isn't thread safe, so using RefCountedThreadSafe won't help. ImageStorage should implement NonThreadSafe to catch such usage.
On Tue, Mar 17, 2015 at 6:31 PM, oshima <osh...@chromium.org> wrote:On Tue, Mar 17, 2015 at 11:39 AM, Dana Jansens <dan...@chromium.org> wrote:On Tue, Mar 17, 2015 at 11:36 AM, Matt Giuca <mgi...@chromium.org> wrote:I've got a CL out to make gfx::Image threadsafe by using RefCountedThreadSafe:It's about 11 months old though and stagnated due to performance concerns (the reviewer, +rsesek, raised performance concerns and I didn't follow up -- sorry about that).I'm happy to push ahead with this CL if we have sufficient motivation to make gfx::Image thread-safe, but I think it would warrant some kind of perf analysis, and I'm not sure what we'd do if we found that it was having an adverse impact on performance.The alternative is to stop reffing the class on multiple threads. We should do one or the other. (I'm all for simpler/less refcounting.)+1. gfx::Image itself isn't thread safe, so using RefCountedThreadSafe won't help. ImageStorage should implement NonThreadSafe to catch such usage.Since "thread safe" is a really ambiguous term, can you clarify what you mean? Assuming it's changed to use RefCountedThreadSafe under the covers, is it invalid to read a gfx::Image from multiple threads at once, or is it only invalid to modify the image from multiple threads at once? Are you worrying about the fact that it's refcounted, so a read-only guarantee has to be about all copies, which might be too difficult to ensure?
On Wed, Mar 18, 2015 at 10:05 AM, Jeffrey Yasskin <jyas...@chromium.org> wrote:On Tue, Mar 17, 2015 at 6:31 PM, oshima <osh...@chromium.org> wrote:On Tue, Mar 17, 2015 at 11:39 AM, Dana Jansens <dan...@chromium.org> wrote:On Tue, Mar 17, 2015 at 11:36 AM, Matt Giuca <mgi...@chromium.org> wrote:I've got a CL out to make gfx::Image threadsafe by using RefCountedThreadSafe:It's about 11 months old though and stagnated due to performance concerns (the reviewer, +rsesek, raised performance concerns and I didn't follow up -- sorry about that).I'm happy to push ahead with this CL if we have sufficient motivation to make gfx::Image thread-safe, but I think it would warrant some kind of perf analysis, and I'm not sure what we'd do if we found that it was having an adverse impact on performance.The alternative is to stop reffing the class on multiple threads. We should do one or the other. (I'm all for simpler/less refcounting.)+1. gfx::Image itself isn't thread safe, so using RefCountedThreadSafe won't help. ImageStorage should implement NonThreadSafe to catch such usage.Since "thread safe" is a really ambiguous term, can you clarify what you mean? Assuming it's changed to use RefCountedThreadSafe under the covers, is it invalid to read a gfx::Image from multiple threads at once, or is it only invalid to modify the image from multiple threads at once? Are you worrying about the fact that it's refcounted, so a read-only guarantee has to be about all copies, which might be too difficult to ensure?RefCountedThreadSafe simply make ref counting thread safe, but not the class itself, and "reading" gfx::Image may modify internal state. For example, AsXxx can methods modifies the internal ImageStorage, so two threads calling these methods can lead to bad state.
Would making something RefCountedThreadSafe give the impression it's safe to use on multiple threads even when it isn't?
Daniel
(I seem to recall a similar thread in the past but I'm having trouble finding it)
--
Would making something RefCountedThreadSafe give the impression it's safe to use on multiple threads even when it isn't?
What I'm thinking about is refcount issues like this:
other_thread->PostTask(..., base::Bind(&DoImageStuff, image));
// Current thread and other thread release refs in a racy manner.
Daniel
What I'm thinking about is refcount issues like this:
other_thread->PostTask(..., base::Bind(&DoImageStuff, image));
// Current thread and other thread release refs in a racy manner.
--
I see, so you are suggesting that for gfx::Image (i.e., a class that has a scoped_refptr to a RefCounted), if you want to create it on Thread A and pass it to Thread B, you create it in a scoped_ptr and pass it via that mechanism. Thus, the Image never gets copied and so its internal refcount remains at 1 during the entire transfer process.
Sorry for not elaborating enough... :( Matt parsed correctly.The case Eric mentioned:
https://code.google.com/p/chromium/codesearch#chromium/src/components/enhanced_bookmarks/bookmark_image_service.cc&q=bookmark_image_service.cc&sq=package:chromium&type=cs&l=239I was planning to allocate |image| in heap at the first place, put inside scoped_ptr, and pass by base::Passed. (At least for the meantime until we find a better solution, we're observing crashes due to this.)
Daniel: I thought a bit about that (basically as a way to let me proceed with adding a DCHECK mechanism to catch thread violations, but allow hand-off from one thread to another). But the problem is it's hard to do the hand-off with layers of containers (like Image).In fact, in my specific instance of this problem, I'm passing a ShortcutInfo to another thread. ShortcutInfo contains an ImageFamily which contains a map of Images which contain a scoped_refptr to an ImageStorage, which is RefCounted. So to do that hand-off correctly, I would have to add a DetachFromThread() delegate method to Image, ImageFamily and ShortcutInfo. That sounds onerous if everybody has to do that to get around the rather blunt DCHECKs.Dana: Can you elaborate on "You need to ensure you pass it back to the original thread to destroy it though." I wasn't aware of this requirement; that sounds like creating an object on one thread and handing it off to another is not safe after all?
If the RefCounted class inherits from NonThreadSafe, then destroying it on the wrong thread will fire a DCHECK.Generally, destroying things on a different thread, when they are not explicitly designed for this is a problem and causes bugs, so that DCHECK seems WAI. Handing it off to another thread to use until its done and gives it back should be safe. Other behaviours sound like they need the class to be thread-safe. Destruction is changing the ref-counts so it would require thread-safe atomic ref counting anyhow.
Oops, sent from wrong email address. Repeating my previous message:Daniel: I thought a bit about that (basically as a way to let me proceed with adding a DCHECK mechanism to catch thread violations, but allow hand-off from one thread to another). But the problem is it's hard to do the hand-off with layers of containers (like Image).In fact, in my specific instance of this problem, I'm passing a ShortcutInfo to another thread. ShortcutInfo contains an ImageFamily which contains a map of Images which contain a scoped_refptr to an ImageStorage, which is RefCounted. So to do that hand-off correctly, I would have to add a DetachFromThread() delegate method to Image, ImageFamily and ShortcutInfo. That sounds onerous if everybody has to do that to get around the rather blunt DCHECKs.Dana: Can you elaborate on "You need to ensure you pass it back to the original thread to destroy it though." I wasn't aware of this requirement; that sounds like creating an object on one thread and handing it off to another is not safe after all?On Wed, 25 Mar 2015 at 10:22 Dana Jansens <dan...@chromium.org> wrote:If the RefCounted class inherits from NonThreadSafe, then destroying it on the wrong thread will fire a DCHECK.Generally, destroying things on a different thread, when they are not explicitly designed for this is a problem and causes bugs, so that DCHECK seems WAI. Handing it off to another thread to use until its done and gives it back should be safe. Other behaviours sound like they need the class to be thread-safe. Destruction is changing the ref-counts so it would require thread-safe atomic ref counting anyhow.Hmm, it doesn't *necessarily* require the class to be thread-safe, in that if you create a class on Thread A, safely hand it off to Thread B (even without the cooperation of that class), and then destroy it on Thread B, you aren't ever going to simultaneously run methods of that class on two threads. So even a non-thread-safe class should support that. But there is the possibility that the class will be specifically designed to be destroyed on a certain thread, so you are right in general.I still think there's a valid case for creating an object on one thread and handing it off to another thread where it will be destroyed, and we should support that if we're going to introduce DCHECKs.
On Tue, Mar 24, 2015 at 4:49 PM, Matt Giuca <mgi...@chromium.org> wrote:Oops, sent from wrong email address. Repeating my previous message:Daniel: I thought a bit about that (basically as a way to let me proceed with adding a DCHECK mechanism to catch thread violations, but allow hand-off from one thread to another). But the problem is it's hard to do the hand-off with layers of containers (like Image).In fact, in my specific instance of this problem, I'm passing a ShortcutInfo to another thread. ShortcutInfo contains an ImageFamily which contains a map of Images which contain a scoped_refptr to an ImageStorage, which is RefCounted. So to do that hand-off correctly, I would have to add a DetachFromThread() delegate method to Image, ImageFamily and ShortcutInfo. That sounds onerous if everybody has to do that to get around the rather blunt DCHECKs.Dana: Can you elaborate on "You need to ensure you pass it back to the original thread to destroy it though." I wasn't aware of this requirement; that sounds like creating an object on one thread and handing it off to another is not safe after all?On Wed, 25 Mar 2015 at 10:22 Dana Jansens <dan...@chromium.org> wrote:If the RefCounted class inherits from NonThreadSafe, then destroying it on the wrong thread will fire a DCHECK.Generally, destroying things on a different thread, when they are not explicitly designed for this is a problem and causes bugs, so that DCHECK seems WAI. Handing it off to another thread to use until its done and gives it back should be safe. Other behaviours sound like they need the class to be thread-safe. Destruction is changing the ref-counts so it would require thread-safe atomic ref counting anyhow.Hmm, it doesn't *necessarily* require the class to be thread-safe, in that if you create a class on Thread A, safely hand it off to Thread B (even without the cooperation of that class), and then destroy it on Thread B, you aren't ever going to simultaneously run methods of that class on two threads. So even a non-thread-safe class should support that. But there is the possibility that the class will be specifically designed to be destroyed on a certain thread, so you are right in general.I still think there's a valid case for creating an object on one thread and handing it off to another thread where it will be destroyed, and we should support that if we're going to introduce DCHECKs.That sounds like a reasonable case for RefCountedThreadSafe? Or do you think that's too heavyweight for this use case?
As I mentioned before, gfx::Image (and other imaged stored in ImageStorage) isn't thread safe, so making gfx::Image (I assume what you really meant is ImageStorage, not gfx::Image itself though) RefCountedThreadSafe can increase confusion and misuse. Even if you make gfx::Image's copy thread-safe, image representations stored in the gfx::Image aren't thread safe, so any attempt to create a copy of gfx::ImageSkia in gfx::Image in different threads can cause similar issue.I assume what you want to achieve is to safely pass an object to another thread? If so, how about creating generic wrapper class that simply move ownership on copy? It prevents a chance for the object to be accessed on two threads.
As I mentioned before, gfx::Image (and other imaged stored in ImageStorage) isn't thread safe, so making gfx::Image (I assume what you really meant is ImageStorage, not gfx::Image itself though) RefCountedThreadSafe can increase confusion and misuse. Even if you make gfx::Image's copy thread-safe, image representations stored in the gfx::Image aren't thread safe, so any attempt to create a copy of gfx::ImageSkia in gfx::Image in different threads can cause similar issue.
As a sort of straw-man, I have created a CL doing what Kibeom suggested for the images around app shortcut creation (which was my original stake in this matter):So just as one data point: I think this was quite an excessive refactor and could present architectural problems in the future. I was forced to make the ShortcutInfo class (which wraps the gfx::Images) non-copyable and convert all clients to pass it around in a scoped_ptr. I had to follow the trail all the way back up into the UI level where the ShortcutInfo was being copied from, and rewrite the code so the ShortcutInfo gets moved in a scoped_ptr, rather than being copied. This makes it impossible to let the dialog box keep a copy of the image that's being written to disk (fortunately, we don't need to do this right now, but it's an example of something that becomes impossible under this scheme).And we're talking about potentially every cross-thread usage of gfx::Image having to go through a similar process. Based on this single data point, I think it's much simpler to convert Image to use RefCountedThreadSafe.
On Wed, Mar 25, 2015 at 12:30 PM oshima <osh...@chromium.org> wrote:As I mentioned before, gfx::Image (and other imaged stored in ImageStorage) isn't thread safe, so making gfx::Image (I assume what you really meant is ImageStorage, not gfx::Image itself though) RefCountedThreadSafe can increase confusion and misuse. Even if you make gfx::Image's copy thread-safe, image representations stored in the gfx::Image aren't thread safe, so any attempt to create a copy of gfx::ImageSkia in gfx::Image in different threads can cause similar issue.I assume what you want to achieve is to safely pass an object to another thread? If so, how about creating generic wrapper class that simply move ownership on copy? It prevents a chance for the object to be accessed on two threads.How is this different/better than scoped_ptr<gfx::Image>? Also, I think I'd be more comfortable if this transfer was explicit rather than on copy.
On Wed, 25 Mar 2015 at 15:30 oshima <osh...@chromium.org> wrote:As I mentioned before, gfx::Image (and other imaged stored in ImageStorage) isn't thread safe, so making gfx::Image (I assume what you really meant is ImageStorage, not gfx::Image itself though) RefCountedThreadSafe can increase confusion and misuse. Even if you make gfx::Image's copy thread-safe, image representations stored in the gfx::Image aren't thread safe, so any attempt to create a copy of gfx::ImageSkia in gfx::Image in different threads can cause similar issue.I think this is making perfect the enemy of good, so to speak.Let's say all I'm trying to do is this (which is true for my use case in app shortcut creation):1. Create an Image on Thread A.2. Pass it to Thread B. Image will not be read or written again on Thread A.3. Read the Image on Thread B.4. Destroy the Image on Thread B.As I see it, there are two ways to accomplish this without a data race:a) Make the ImageStorage use RefCountedThreadSafe, orb) Wrap the Image in a scoped_ptr and pass it to the other thread without touching the ref count.Now, neither of these approaches solve the problem of the thread-safety of the underlying ImageSkia.
Depending on your use case, that may or may not be a problem. In my use case, I don't think it is a problem, but in other use cases (concurrently reading or writing the image), it would still be a problem. Crucially, it's still a problem for both approach (a) and (b).
So the fact that (a) won't make Image completely thread-safe cannot be used as an argument in favour of (b). The fact is that (a) is a partial solution to the problem, and I think (having fully implemented both solutions) that (a) is a much simpler, less error-prone and general solution than (b).
I don't think we should let the fact that it is not a complete thread-safety solution stop us from going ahead with it as a partial solution (as long as the documentation for Image still states that it is not thread-safe).
Yes, that's because that's different issue. There are two kinds of "thread-safety".1) an object can be passed/shared between multiple objects and can be safely destroyed.a) If you need to copy reference on multiple threads at the same time, you have to use RefCountedThreadSafe.This needs extra caution because "using" such object from multiple thread isn't guaranteed to be safe, unlessthe object is designed to be thread safe.b) If you just need to pass an object to another thread, and the object will only be used on that thread, you don't have to use RefCountedThreadSafe.2) an object can be accessed from multiple threads safely. RefCountedThreadSafe won't solve this.
My understanding is that you're trying to solve 1.b).
The code may look simpler but implication is not. I understand that you want to simplify the code, and that's why I suggested to create a wrapper. It'd be like unique_ptr, but limited. I believe it won't make the code much more complicated.
Yes, that's because that's different issue. There are two kinds of "thread-safety".1) an object can be passed/shared between multiple objects and can be safely destroyed.a) If you need to copy reference on multiple threads at the same time, you have to use RefCountedThreadSafe.This needs extra caution because "using" such object from multiple thread isn't guaranteed to be safe, unlessthe object is designed to be thread safe.b) If you just need to pass an object to another thread, and the object will only be used on that thread, you don't have to use RefCountedThreadSafe.2) an object can be accessed from multiple threads safely. RefCountedThreadSafe won't solve this.Thanks for breaking it down into numbers and letters. Very useful for reference.My understanding is that you're trying to solve 1.b).Well, I'm technically trying to solve 1a, but my use case is fairly close to 1b.That is: the current use of gfx::Image (in my use case of shortcut creation) is absolutely 1a, in that we have a reference to the gfx::Image in a dialog box. The dialog box passes a copy of the gfx::Image to the FILE thread, while still holding a reference to it. Then it closes, releasing its handle on the gfx::Image. (By "coincidence", it closes immediately after sending the image to the FILE thread, but we could easily keep the dialog open for further user input.)So that is 1a "you need to copy reference on multiple threads at the same time", which is why I've been suggesting we use RefCountedThreadSafe. Maybe it's overkill to convert the entire Image class, but I'm guessing there are other uses of gfx::Image that also fall into 1a (because we are seeing TSan errors on other usages of gfx::Image besides mine).Having said all that, my use case is reasonably close to 1b, in that I technically don't need the gfx::Image in the dialog box after passing it to the FILE thread. Converting my use case to 1b is the subject of https://codereview.chromium.org/1038573002/ which I mentioned earlier. My point is that it made my code quite a bit more constrained (in how it can be extended in the future). All other things being equal, I'd rather be allowed to write 1a uses of gfx::Image, than have all clients forced to do 1b.The code may look simpler but implication is not. I understand that you want to simplify the code, and that's why I suggested to create a wrapper. It'd be like unique_ptr, but limited. I believe it won't make the code much more complicated.You're basically suggesting that I use scoped_ptr. (I could make a wrapper to avoid the syntactic overhead of writing "scoped_ptr" everywhere.) The issue I have is not syntactic overhead. It's that throughout the entire codebase, every object that holds a reference to a gfx::Image that might be transferred to another thread at some point in the future must be non-copyable and single-owned (either inside a scoped_ptr, or some equivalent mechanism).I can do this. I've done it on that CL. But I just want to be clear about the architectural (not syntactic) burden that this potentially places on all clients.
You're basically suggesting that I use scoped_ptr. (I could make a wrapper to avoid the syntactic overhead of writing "scoped_ptr" everywhere.) The issue I have is not syntactic overhead. It's that throughout the entire codebase, every object that holds a reference to a gfx::Image that might be transferred to another thread at some point in the future must be non-copyable and single-owned (either inside a scoped_ptr, or some equivalent mechanism).I can do this. I've done it on that CL. But I just want to be clear about the architectural (not syntactic) burden that this potentially places on all clients.It may be just me but I generally find it to be the opposite. Ref-counting adds a burden of complexity in that now we have email threads just as this one. Single ownership is very clear about where things are owned and where they are destroyed. You can always keep around raw pointers if you want to access it in more than one place, you just need to coordinate the lifetime, which makes the code explicit. It requires more thought when writing code, but improves understanding of it for others, and hackability in the future, IMHO.
Right. I'm totally in agreement (with Dana and Peter) about single ownership vs ref counting. I'm a huge fan of C++s default mentality of everything is a value with clear ownership. I'm not trying to argue for reference counting.The problem here is that Image is already refcounted, and that means it breaks the C++ default value semantics for everything that contains it (ImageFamily, ShortcutInfo, and so on). I'm used to things either being non-copyable, or copyable with deep copy semantics. What's murky about this is that normally, I only have to think about thread safety when I pass a pointer (or scoped_refptr) to an object on another thread. Image is forcing me to consider thread safety of passing an object by value to another thread. There is the problem (and my suggestion is that an object that pretents to be a value but secretly refcounts behind the scenes should have the courtesy of also secretly being thread-safe).Perhaps the correct answer is "just assume Image is non-copyable" (which is effectively what I'm doing in my CL). That demonstrates the weirdness Ben is talking about: having an object that is conceptually "non-copyable" but with a reference count of exactly 1 inside it. But yeah, I'm happy to go ahead with this since it's a localized fix that won't require changing the way this heavily-used class works.
I wrapped gfx::Image by scoped_refptr.
Perhaps you could directly use an ImageSkia instead of an Image? Then you would have just two layers of ref counting instead of four.
How about implementing Pass(), which transfers ownership of the storage? (probably with check if the ref count is 1) That can also prevent the instance being shared with threads.