Binder 的交易模型允許重入,因此即使程序只有單一繫結器執行緒,您仍需要鎖定。舉例來說,假設您在單一執行緒程序 A 中疊代清單,針對清單中的每個項目,您會建立外送繫結器交易。如果您呼叫的函式實作項目會對程序 A 中代管的節點建立新的繫結器交易,則該交易會在疊代清單的同一執行緒上處理。如果該交易的實作項目修改了相同清單,您稍後繼續疊代清單時可能會遇到問題。
[[["容易理解","easyToUnderstand","thumb-up"],["確實解決了我的問題","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["缺少我需要的資訊","missingTheInformationINeed","thumb-down"],["過於複雜/步驟過多","tooComplicatedTooManySteps","thumb-down"],["過時","outOfDate","thumb-down"],["翻譯問題","translationIssue","thumb-down"],["示例/程式碼問題","samplesCodeIssue","thumb-down"],["其他","otherDown","thumb-down"]],["上次更新時間:2025-07-29 (世界標準時間)。"],[],[],null,["# Handle threads\n\nBinder's threading model is designed to facilitate local function calls even\nthough those calls might be to a remote process. Specifically, any process\nhosting a node must have a pool of one or more binder threads to handle\ntransactions to nodes hosted in that process.\n\nSynchronous and asynchronous transactions\n-----------------------------------------\n\nBinder supports synchronous and asynchronous transactions. The following\nsections explain how each transaction type is executed.\n\n### Synchronous transactions\n\nSynchronous transactions block until they have been executed on the node, and a\nreply for that transaction has been received by the caller. The following figure\nshows how a synchronous transaction is executed:\n\n**Figure 1.** Synchronous transaction.\n\nTo execute a synchronous transaction, binder does the following:\n\n1. The threads in the target threadpool (T2 and T3) call into the kernel driver to wait for incoming work.\n2. The kernel receives a new transaction and wakes up a thread (T2) in the target process to handle the transaction.\n3. The calling thread (T1) blocks and waits for a reply.\n4. The target process executes the transaction and returns a reply.\n5. The thread in the target process (T2) calls back into the kernel driver to wait for new work.\n\n### Asynchronous transactions\n\nAsynchronous transactions don't block for completion; the calling thread\nunblocks as soon as the transaction has been passed into the kernel. The\nfollowing figure shows how an asynchronous transaction is executed:\n\n**Figure 2.** Asynchronous transaction.\n\n1. The threads in the target threadpool (T2 and T3) call into the kernel driver to wait for incoming work.\n2. The kernel receives a new transaction and wakes up a thread (T2) in the target process to handle the transaction.\n3. The calling thread (T1) continues execution.\n4. The target process executes the transaction and returns a reply.\n5. The thread in the target process (T2) calls back into the kernel driver to wait for new work.\n\n### Identify a synchronous or asynchronous function\n\nFunctions marked as `oneway` in the AIDL file are asynchronous. For example: \n\n oneway void someCall();\n\nIf a function isn't marked as `oneway`, it's a synchronous function, even if\nthe function returns `void`.\n| **Note:** The process containing the callee can die or freeze without processing a function call and without providing any failure.\n\nSerialization of asynchronous transactions\n------------------------------------------\n\nBinder serializes asynchronous transactions from any single node. The following\nfigure shows how binder serializes asynchronous transactions:\n\n**Figure 3.** Serialization of asynchronous transactions.\n\n1. The threads in the target threadpool (B1 and B2) calls into the kernel driver to wait for incoming work.\n2. Two transactions (T1 and T2) on the same node (N1) are sent to the kernel.\n3. The kernel receives a new transactions and, because they are from the same node (N1), serializes them.\n4. Another transaction on a different node (N2) is sent to the kernel.\n5. The kernel receives the third transaction and wakes up a thread (B2) in the target process to handle the transaction.\n6. The target processes execute each transaction and returns a reply.\n\n| **Note:** Asynchronous transactions on the same node aren't always handled by the same thread in the threadpool. Instead, they can be handled on different threads, but never at the same time.\n\nNested transactions\n-------------------\n\nSynchronous transactions can be nested; a thread that is handling a\ntransaction can issue a new transaction. The nested transaction can be to a\ndifferent process, or to the same process that you received the current\ntransaction from. This behavior mimics local function calls. For example,\nsuppose you have a function with nested functions: \n\n def outer_function(x):\n def inner_function(y):\n def inner_inner_function(z):\n\nIf these are local calls, they are executed on the same thread.\nSpecifically, if the caller of `inner_function` also happens to be the process\nhosting the node that implements `inner_inner_function`, the call to\n`inner_inner_function` is executed on the same thread.\n\nThe following figure shows how binder handles nested transactions:\n\n**Figure 4.** Nested transactions.\n\n1. Thread A1 requests running `foo()`.\n2. As part of this request, thread B1 runs `bar()` which A runs on the same thread A1.\n\nThe following figure shows thread execution if the node that implements\n`bar()` is in a different process:\n\n**Figure 5.** Nested transactions in different processes.\n\n1. Thread A1 requests running `foo()`.\n2. As part of this request, thread B1 runs `bar()` which runs in another thread C1.\n\nThe following figure shows how the thread reuses the same process anywhere in\nthe transaction chain:\n\n**Figure 6.** Nested transactions reusing a thread.\n\n1. Process A calls into process B.\n2. Process B calls into process C.\n3. Process C then makes a call back into process A and the kernel reuses the thread A1 in process A that is part of the transaction chain.\n\nFor asynchronous transactions, nesting doesn't play a role; the client doesn't\nwait for the result of an asynchronous transaction, so there is no nesting.\nIf the handler of an asynchronous transaction makes a call into\nthe process that issued that asynchronous transaction, that transaction can be\nhandled on any free thread in that process.\n\nAvoid deadlocks\n---------------\n\nThe following image shows a common deadlock:\n\n**Figure 7.** Common deadlock.\n\n1. Process A takes mutex MA and makes a binder call (T1) to process B which also attempts to take mutex MB.\n2. Simultaneously, process B takes mutex MB and makes a binder call (T2) to process A which attempts to take mutex MA.\n\nIf these transactions overlap, each transaction could potentially take a\nmutex in their process while waiting for the other process to release a mutex,\nresulting in a deadlock.\n\nTo avoid deadlocks while using binder, don't hold any lock when making a binder\ncall.\n\n### Lock ordering rules and deadlocks\n\nWithin a single execution environment, deadlock is often avoided with a\nlock ordering rule. However, when making calls between processes and between\ncodebases, especially as code gets updated, it's impossible to maintain and\ncoordinate an ordering rule.\n\n#### Single mutex and deadlocks\n\nWith nested transactions, process B can call directly back\ninto the same thread in process A holding a mutex. Therefore, due to unexpected\nrecursion, it's still possible to get a deadlock with a single mutex.\n\n#### Synchronous calls and deadlocks\n\nWhile asynchronous binder calls don't block for completion, you should\nalso avoid holding a lock for asynchronous calls. If you hold a lock, you might\nexperience locking issues if a one-way call is accidentally changed to a\nsynchronous call.\n\n#### Single binder thread and deadlocks\n\nBinder's transaction model allows for reentrancy, so even if a process has\na single binder thread, you still need locking. For example, suppose you're\niterating over a list in a single-threaded process A. For each item in the\nlist, you make an outgoing binder transaction. If the implementation of the\nfunction you are calling makes a new binder transaction to a node hosted in\nprocess A, that transaction is handled on the same thread that was iterating the\nlist. If the implementation of that transaction modifies the same list, you\ncould experience issues when you continue iterating over the list later.\n\nConfigure threadpool size\n-------------------------\n\nWhen a service has multiple clients, adding more threads to the threadpool can\nreduce contention and serve more calls in parallel. After you deal with\nconcurrency correctly, you can add more threads. An issue that can be caused by\nadding more threads that some threads might not be used during quiet workloads.\n| **Note:** As with ordinary, non-binder, function calls, you need to consider concurrency caused by reentrant calls.\n\nThreads are spawned on-demand until a configured maximum After a\nbinder thread has been spawned, it stays alive until the process hosting it\nends.\n\nThe libbinder library has a default of 15 threads. Use\n`setThreadPoolMaxThreadCount` to change this value: \n\n using ::android::ProcessState;\n ProcessState::self()-\u003esetThreadPoolMaxThreadCount(size_t maxThreads);"]]