Thread: mutex necessity

  1. #1
    Alessio Stella
    Join Date
    May 2008
    Location
    Italy, Bologna
    Posts
    251

    mutex necessity

    I wonder wether pthreads can share variables safely, without using mutex, in the following special cases:
    (1)
    a structure or array is shared but each single element of the array, or field of the structure, is not shared.
    Probably it is also necessary the assumption that these data are extern or static
    Example :
    pthread 1 uses only Struct[0].field1 , Struct[0].field2 and Struct[1].field3
    pthread 2 uses only Struct[1].field1 and Struct[0].field3

    (2)
    from a certain moment on I am sure that some data are only read by (and not written by) all threads
    Probably it is also necessary the assumption that these data are extern or static
    Example:
    Struct[whatever].fieldAny can be read by any thread but no one will write it

    (3)
    Other special question:
    can pthreads share a mutex directly or do they have to access it via separate pointers?
    Example:
    pthread1 calls pthread_mutex_lock(&mutex) ... pthread_mutex_unlock(&mutex)
    pthread2 calls pthread_mutex_lock(&mutex) ... pthread_mutex_unlock(&mutex)

    or is it necessary that
    main thread runs mutex1=&mutex mutex2=&mutex then creates thread1 and thread2 where
    pthread1 calls pthread_mutex_lock(mutex1) ... pthread_mutex_unlock(mutex1)
    pthread2 calls pthread_mutex_lock(mutex2) ... pthread_mutex_unlock(mutex2)



    Thank you for help

  2. #2
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    In response to your two scenarios:

    1. If two threads will write to a variable, then you probably need a mutex. If one is writing and one is reading and you are not worried about writing/reading out of sync, then you should be fine without one.... (ie. one thread reads an old value of the struct field, etc. etc..). Otherwise, if this is a producer/consumer type of situation, then you need a mutex. In general, the need for a mutex depends not on whether multiple threads access the same variable, but how they access it, and the requirements as to how they need to access it.
    2. If no writing is taking place (ie. the value is const or assigned before the threads are started), then you don't need a mutex. What order the threads read should be irrelevant in such a case.

  3. #3
    Registered User C_ntua's Avatar
    Join Date
    Jun 2008
    Posts
    1,853
    3) They can call the same mutex. I believe it is guaranteed that only one will get the lock.

    2) Reading a variable doesn't need syncrhonization. If two threads require the same variable to read, then the bus controller will serialize the "require" and give the values to each thread. The problem is with writing.
    A classic example
    Thr1: r = 2;
    Thr2: r = 1;

    Both threads read r. It doesn't matter who reads first. It matters who writes last. That will determine r value. If you have:

    Thr1: r+= 2;
    Thr2: r = 1;

    Then the write (for the same variable) makes it necessary for synchronizing the oprerations.

    1) So you can read Struct[0].field with Thr1 and Struct[0].field2 with Thr2 and change their value safely. Since the data is in different memory location.
    In general, you can safely read Struct[0], since its value cannot be changed, and safely read/write its struct fields since they aren't shared, but each thread reads different memory locations.

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by C_ntua View Post
    3) They can call the same mutex. I believe it is guaranteed that only one will get the lock.
    Of course it's guaranteed. Otherwise there would be no use for mutexes.

    2) Reading a variable doesn't need syncrhonization. If two threads require the same variable to read, then the bus controller will serialize the "require" and give the values to each thread.
    I don't think that's a given. I believe (some) architectures can indeed process multiple read requests at the same time. Thus they need not be serialized.
    Regardless, if threads only reads, the data will never change and regardless who reads first and who reads last or if one thread reads half and then the second thread starts to read, it doesn't matter, because the value will always be the same.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    1) There are no portable guarantees of safety due to word tearing - which Posix does not address. There are ways to improve (portability) safety, but there's still no portable guarantees of safety. More details at this comp.programming.threads thread: http://groups.google.com/group/comp....a9c0ee17e390c/

    2) As per 4.10 of the Posix standard, this is ok - as long as the data was initialized or set prior to the threads being created. http://www.opengroup.org/onlinepubs/...bd_chap04.html
    >> Probably it is also necessary ... that these data are extern or static
    No.

    3) Both or OK. What you must never do is make a copy of the pthread_mutex_t object itself. You can make copies of the pointer and use them.

    gg

  6. #6
    Alessio Stella
    Join Date
    May 2008
    Location
    Italy, Bologna
    Posts
    251
    [QUOTE=Codeplug;767583]1) There are no portable guarantees of safety due to word tearing - which Posix does not address. There are ways to improve (portability) safety, but there's still no portable guarantees of safety. More details at this comp.programming.threads thread: http://groups.google.com/group/comp....a9c0ee17e390c/

    The point you move is very interesting but astonishing. So you're telling me that on a Linux platform any data smaller than (I guess) 4 bytes is not safe? Or even a 4 byte integer is not safe if put after a 2 bytes variable (if the compiler for some reason did not pad) together in a struct??!
    Gosh

  7. #7
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    More specifically, you are in danger of having word-tearing if two threads write to adjacent memory locations, and both of those locations fit within the natural memory granularity of the processor.

    Using non-standard compiler features can help mitigate this risk. For example, GCC's "__attribute__ (aligned(#))", or MSVC's "__declspec(align(#))" to force the compiler to align members to a particular granularity. You also have to be careful when using dynamic memory - for instance, malloc may not return memory that sufficiently aligned. There are non-standard functions for this such as the MS-CRT's _aligned_malloc().

    Having said all that - a memory-access design such as 1) will cause "false sharing" or "cache thrashing". This is when two threads are modifying data within the same processor cache-line - where each independent modification doesn't need to be "communicated" to any other cores.

    Ideally, if thread 1 (T1) modifies a local data set 1 (S1), and T2 modifies S2, then S1 and S2 would be at least "cache-line-size" apart from one another.

    Here's a good "cache 101" article. The "Cache Loading" section talks about false sharing. http://developer.amd.com/Membership/...eloper.amd.com

    So in the end, a design such as 1) should be avoided.

    gg

  8. #8
    Alessio Stella
    Join Date
    May 2008
    Location
    Italy, Bologna
    Posts
    251
    Ok very interesting
    Last edited by mynickmynick; 07-14-2008 at 04:06 AM.

  9. #9
    Alessio Stella
    Join Date
    May 2008
    Location
    Italy, Bologna
    Posts
    251
    Quote Originally Posted by Codeplug View Post
    So in the end, a design such as 1) should be avoided.

    gg
    Ok very interesting
    So you're telling me that design (1) is bug/error safe in case if field1,field2,field3 etc. have size multiple of processor memory granularity?
    But still it can be very inefficient if field1,2,3.. have not size multiple of cache line size in a multicore or multiprocessor system ?
    Last edited by mynickmynick; 07-14-2008 at 04:13 AM.

  10. #10
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> ... have size multiple of processor memory granularity?
    *And* are aligned to it as well.

    >> But still it can be very inefficient...
    Correct.

    Just to re-iterate David Butenhof's position:
    "The best strategy would probably be to say that AN array or A structure is an "atomicity unit"."

    In other words, just don't write to individual struct or array members across multiple threads. If re-designing and re-writing *really* isn't an option - then you can use compiler support to ensure proper alignment and padding of struct members. Ways to this with GCC are discussed in this thread: http://groups.google.com/group/comp....0feda6bf72801a

    gg

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Mutex and Shared Memory Segment Questions.
    By MadDog in forum Linux Programming
    Replies: 14
    Last Post: 06-20-2010, 04:04 AM
  2. mutex problem
    By radeberger in forum C++ Programming
    Replies: 16
    Last Post: 03-20-2009, 04:24 PM
  3. Yet another n00b in pthreads ...
    By dimis in forum C++ Programming
    Replies: 14
    Last Post: 04-07-2008, 12:43 AM
  4. Thread Synchronization in Win32
    By passionate_guy in forum C Programming
    Replies: 0
    Last Post: 02-06-2006, 05:34 AM
  5. Mutex - location of lock/unlock
    By cjschw in forum C++ Programming
    Replies: 1
    Last Post: 08-14-2003, 12:28 PM