Multithreading programming principles and differences between SEM semaphores and mutex locks (1)

Source: Internet
Author: User
Tags semaphore

1. Try to use the mutex concept to design the architecture
2. Common Problems
A. Loop deadlock (mutex lock)
B. Non-recursive deadlock
C. Data is not synchronized
D. excessively active garbage collection and memory cleanup
3. Several principles
A. Private operations as much as possible
B. The public method can be called at any thread or at any time.
C. Use mutex instead of semaphores as much as possible.
D. You must determine the potential assumptions. Are they in line with the actual conditions?
E. After obtaining the lock, do as few operations as possible to avoid continuing to call the resource lock within get ().

4. What are the advantages and disadvantages of SEM and mutex processing?

I have summarized the following table: (it is inevitable that there are deficiencies. Please give me more advice !)

SEM Mutex
Powerful SEM, difficult to locate Problems Mutex features stable and easy to locate Problems
Protects resource pool sharing Control a single resource
Inter-process communication and inter-thread Communication Inter-thread Communication
Multi-thread and multi-task synchronization Multi-thread and multi-task mutex
Computing or data processing is supported. It must be locking a resource.

5. Implementation Mechanism of SEM and mutex

In Linux, semaphores and thread mutex locks are implemented through the futex system.

Futex is a basic tool for locking and building high-level abstract locks such as semaphores and POSIX mutex on Linux. They first appeared in version 2.5.7 developed by the kernel. Their semantics was fixed in version 2.5.40 and then appeared in the kernel of 2.6.x series stable version.

Futex is short for fast userspace mutex, which means a fast user space mutex. The Linux kernel uses them as pre-fabricated components for Fast User space locks and semaphores. Futex is very basic. With its own excellent performance, it builds an abstraction of higher-level locks, such as POSIX mutex. Most programmers do not need to use futex directly. It is generally used to implement a system library like nptl.

Futex consists of a memory space (an aligned integer variable) that can be shared by multiple processes; the value of this integer variable can be increased or decreased by calling the atomic operation commands provided by the CPU through the assembly language, and a process can wait until the value changes to a positive number. Almost all futex operations are completed in the application space. Only when the operation results are inconsistent and need to be arbitrated will the operation be executed in the operating system kernel space. This mechanism allows the use of the futex lock primitive to have a very high execution efficiency: because the vast majority of operations do not need to be arbitrated between multiple processes, most operations can be executed in the application space, instead of using (relatively costly) kernel system calls.

Futex is stored in the shared memory of the user space and operated through atomic operations. In most cases, if the resource does not compete for use, the process or thread can immediately obtain the resource success. In fact, there is no need to call the system call and the system is stuck in the kernel. In fact, the function of futex is to reduce the number of system calls and improve the system performance.6. Implementation principle of SEM and mutex

Implementation principle of thread mutex pthread_mutex_t:

Atomic_dec (pthread_mutex_t.value); <br/> If (pthread_mutex_t.value! = 0) <br/> futex (wait) <br/> else <br/> success </P> <p> pthread_mutex_unlock: <br/> atomic_inc (pthread_mutex_t.value ); <br/> If (pthread_mutex_t.value! = 1) <br/> futex (wakeup) <br/> else <br/> success

Implementation principle of sem_t:

Sem_wait (sem_t * SEM) <br/>{< br/> for (;) {</P> <p> If (atomic_decrement_if_positive (SEM-> count )) <br/> break; </P> <p> futex_wait (& SEM-> count, 0) <br/>}</P> <p> sem_post (sem_t * SEM) <br/>{< br/> N = atomic_increment (SEM-> count ); <br/> // pass the new value of SEM-> count <br/> futex_wake (& SEM-> count, n + 1); <br/>}

Compared with the implementation of pthread_mutex_unlock () and sem_post (), we find that, in any case, sem_post () will call futex_wake () for system calling. However, pthread_mutex_unlock () is in line with the original intention of futex, and futex_wake () is called only when arbitration is required (). So What Are arbitration conditions?

As mentioned above, the semantic difference between semaphores and thread mutex locks is that the semaphores value> = 0, while the value of thread mutex locks can be negative.
There is no difference between the two lock operations. A semaphore can obtain resources as long as the value is greater than 0. The thread mutex lock requires value = 1.
But for the unlock operation, there are some differences between the two. The semaphore and thread mutex lock increase the corresponding value. If the value is 1 after 1 is added, for the thread mutex lock, the resource is actually available, and no other thread is waiting for this resource; otherwise, other threads are waiting for this resource, you need to call the futex system call to wake them up. However, for semaphores, the value must be greater than or equal to 0. After adding 1, even if the value is 1, it cannot be determined that there are no other processes or threads waiting for resources. Therefore, the futex system must be called. For example:

# Include <stdio. h> <br/> # include <semaphore. h> <br/> # include <pthread. h> </P> <p> sem_t sem_a; <br/> void * task1 (); </P> <p> int main (void) <br/>{< br/> int ret = 0; <br/> pthread_t thrd1; <br/> pthread_t thrd2; <br/> sem_init (& sem_a, 0, 1 ); <br/> ret = pthread_create (& thrd1, null, task1, null); // create a sub-thread <br/> ret = pthread_create (& thrd2, null, task1, null); // create a subthread <br/> pthread_join (thrd1, null); // wait until the subthread ends <br/> pthread_join (thrd2, null ); // wait until the sub-thread ends <br/>}</P> <p> void * task1 () <br/>{< br/> int sval = 0; <br/> sem_wait (& sem_a); // hold the semaphore <br/> sleep (5); // do_nothing <br/> sem_getvalue (& sem_a, & sval ); <br/> printf ("SEM value = % d/N", sval); <br/> sem_post (& sem_a); // release semaphores <br/>}

The above SEM value is initialized to 1, but there are two threads competing for resources. Then the first thread gets the resource successfully. When it is unlocked, the value of SEM becomes 1. However, there is actually a thread waiting for resources at this time. Therefore, you must call the futex_wake () system to wake up the thread waiting for resources.

 

Thanks for the following Blog content!

Http://www.eetop.cn/blog/html/04/343504-14125.html

Http://dev.firnow.com/course/6_system/linux/Linuxjs/20090901/173322.html

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.