Multi-threaded file management method and apparatus, storage medium, and electronic device
By using a descriptor mapping table to manage the mapping relationship between security descriptors and actual file descriptors in a multi-threaded environment, the problem of low security in file descriptor management is solved, resource access isolation and consistency are achieved, and the security and stability of the application are improved.
Patent Information
- Application Number
- CN202511295874.9
- Authority / Receiving Office
- CN · China
- Patent Type
- Patents(China)
- Current Assignee / Owner
- Filing Date
- 2025-09-11
- Publication Date
- 2025-11-21
- Estimated Expiration
- 2045-09-11
AI Technical Summary
In a multithreaded environment, file descriptor management has low security issues, leading to undefined behaviors such as data corruption or program crashes. This is especially true in high-concurrency web servers and database management systems, where threads may misuse closed descriptors, resulting in data corruption or information leakage.
A descriptor mapping table is introduced to store the mapping relationship between security descriptors (first descriptors) and actual file descriptors (second descriptors). The security descriptor receives the close command, finds and deletes the mapping relationship, and ensures that only the correct resources are closed, preventing descriptor reuse and inconsistent resource states.
It significantly reduces the risk of resource conflicts and data corruption, ensures the consistency of file resource states, improves the security and stability of applications, and avoids errors caused by inconsistent resource states between threads.
Smart Images

Figure CN120763121B_ABST
Abstract
Description
Technical Field
[0001] This application relates to the field of file management, and more particularly to a multi-threaded file management method and apparatus, storage medium and electronic device. Background Technology
[0002] In traditional Unix / Linux environments, a file descriptor (FD) is a handle used by a process to access files and other I / O resources. The problem becomes complex when multiple threads share the same process space and attempt to access the same file descriptor concurrently. For example, in a high-concurrency web server, multiple threads may need to simultaneously read and write log files or maintain network connections with clients. In a database management system, threads may need to access multiple data files or index files simultaneously to perform complex queries and transactions.
[0003] In a multi-threaded environment, file descriptor management still faces the following drawbacks: If one thread closes a file descriptor while other threads are still using it, those threads may continue to attempt to read or write to a closed descriptor, leading to undefined behavior such as data corruption or program crashes. When a file descriptor is reassigned to another file after being closed, if the old thread is unaware of the descriptor's closure or reuse and continues to use the original descriptor, it may write to or read from incorrect files, resulting in data corruption or information leakage. In other words, file descriptor management methods in related technologies suffer from low security. Summary of the Invention
[0004] This application provides a multi-threaded file management method and apparatus, storage medium and electronic device, to at least solve the problem of low security in file descriptor management methods in related technologies.
[0005] This application provides a multi-threaded file management method, including: receiving a first instruction sent by a first thread, wherein the first instruction is used to instruct the closing of a target file, and the first instruction includes a first descriptor;
[0006] Access the descriptor mapping table to find the second descriptor corresponding to the first descriptor. The second descriptor is used to indicate the target file, and the descriptor mapping table is used to store the mapping relationship between the first descriptor and the second descriptor.
[0007] If the first descriptor exists in the descriptor mapping table, delete the mapping relationship and close the target file based on the second descriptor.
[0008] This application also provides a multi-threaded file management device, including: a first receiving module, configured to receive a first instruction sent by a first thread, wherein the first instruction is used to instruct the closing of a target file, and the first instruction includes a first descriptor;
[0009] The lookup module is used to access the descriptor mapping table and look up the second descriptor corresponding to the first descriptor. The second descriptor is used to indicate the target file, and the descriptor mapping table is used to store the mapping relationship between the first descriptor and the second descriptor.
[0010] The mapping table adjustment module is used to delete the mapping relationship and close the target file based on the second descriptor if the first descriptor exists in the descriptor mapping table.
[0011] This application also provides an electronic device, including: a memory for storing a computer program; and a processor for implementing any of the above-described multithreaded file management methods when executing the computer program.
[0012] This application also provides a computer-readable storage medium storing a computer program, wherein when the computer program is executed by a processor, it implements the steps of any of the above-described multithreaded file management methods.
[0013] This application also provides a computer program product, including a computer program that, when executed by a processor, implements the steps of any of the above-described multithreaded file management methods.
[0014] This application receives a first instruction sent by a first thread, wherein the first instruction is used to instruct the closing of a target file, and the first instruction includes a first descriptor; it accesses a descriptor mapping table to find a second descriptor corresponding to the first descriptor, wherein the second descriptor is used to indicate the target file, and the descriptor mapping table is used to store the mapping relationship between the first descriptor and the second descriptor; if the first descriptor exists in the descriptor mapping table, the mapping relationship is deleted, and the target file is closed based on the second descriptor. By introducing the concepts of a first descriptor (i.e., a security descriptor) and a second descriptor (i.e., the actual file descriptor), the risk of resource conflicts and data corruption can be significantly reduced when resources are shared between multiple threads or processes. When a thread issues a close command (the first instruction), the system first searches the descriptor mapping table for the actual file descriptor associated with the security descriptor, ensuring that only the correct resource is closed. After finding the second descriptor in the descriptor mapping table, the mapping relationship between the first descriptor and the second descriptor is immediately deleted. This means that once a resource is closed, the security descriptor will no longer be mapped to any system resource, preventing descriptor reuse and avoiding threads misusing closed resources. By querying and updating the file descriptor mapping table, the consistency of file resource status is ensured. In a multi-threaded environment, each thread uses an independent security descriptor to reference resources, which helps isolate resource access between threads and avoids errors caused by inconsistent resource states. Therefore, this addresses the technical problem of low security in current file descriptor management methods, thereby improving application security. Attached Figure Description
[0015] To more clearly illustrate the embodiments of this application, the accompanying drawings used in the embodiments will be briefly introduced below. Obviously, the drawings described below are only some embodiments of this application. For those skilled in the art, other drawings can be obtained based on these drawings without creative effort.
[0016] Figure 1 This is a schematic diagram of the hardware environment for an optional multi-threaded file management method according to an embodiment of this application;
[0017] Figure 2 This is a flowchart of an optional multi-threaded file management method according to an embodiment of this application;
[0018] Figure 3 This is a schematic diagram of an optional safety shutdown process according to an embodiment of this application;
[0019] Figure 4 This is a schematic diagram of an optional secure opening process according to an embodiment of this application;
[0020] Figure 5 This is a schematic diagram of an optional secure write process according to an embodiment of this application;
[0021] Figure 6 This is a schematic diagram of an optional multi-threaded file management method according to an embodiment of this application;
[0022] Figure 7 This is a schematic diagram of another optional multi-threaded file management according to an embodiment of this application;
[0023] Figure 8 This is a structural block diagram of an optional multi-threaded file management device according to an embodiment of this application. Detailed Implementation
[0024] The technical solutions of the embodiments of this application will be clearly and completely described below with reference to the accompanying drawings. Obviously, the described embodiments are only some embodiments of this application, and not all embodiments. Based on the embodiments of this application, all other embodiments obtained by those of ordinary skill in the art without creative effort are within the protection scope of this application.
[0025] It should be noted that, in the description of this application, the terms "comprising," "including," or any other variations thereof are intended to cover non-exclusive inclusion, such that a process, method, article, or apparatus that comprises a list of elements includes not only those elements but also other elements not expressly listed, or elements inherent to such a process, method, article, or apparatus. The terms "first," "second," etc., in this application are used to distinguish similar objects and are not used to describe a specific order or sequence.
[0026] To enable those skilled in the art to better understand the present application, the present application will be further described in detail below with reference to the accompanying drawings and specific embodiments.
[0027] According to one aspect of the embodiments of this application, a multi-threaded file management method is provided. As an optional implementation, the above-described multi-threaded file management method can be applied to, but is not limited to, applications such as... Figure 1 The illustrated hardware environment includes a multi-threaded file management system. This multi-threaded file management system may include, but is not limited to, server 102, network 104, and disk array 106. Server 102 runs the target client.
[0028] Server 102 can execute step S102, where the first thread in the central processing unit (CPU) of server 102 generates a first instruction and executes steps S104-S106, accesses the descriptor mapping table, finds the second descriptor corresponding to the first descriptor, deletes the mapping relationship if the first descriptor exists in the descriptor mapping table, and executes step S108, closes the target file based on the second descriptor.
[0029] It should be noted that practical applications can be found in high-concurrency, multi-threaded server systems, especially in areas where file operation security is extremely important, such as database servers, financial trading systems, and large enterprise application servers.
[0030] For example, a database server handling multiple concurrent transactions needs to frequently read and write files on disk. In a multithreaded model, each transaction may be handled by different threads, and these threads may need to share certain file resources. The first instruction is issued by a thread (which can be called the "first thread") to instruct the closing of a target file. The first instruction contains the first file descriptor (i.e., the security descriptor safe_fd), which is generated by the security management layer when the file is opened, serving as the front-end interface for file operations.
[0031] Upon receiving the first instruction, the security management layer executes the step "access the descriptor mapping table." This operation, also performed by the security management layer, targets the descriptor mapping table. The descriptor mapping table is a key data structure maintained by the security management layer, storing the mapping between security descriptors and actual descriptors (i.e., the operating system-level file descriptor `real_fd`), as well as status entry information. By searching the mapping table for the entry associated with the first descriptor, the security management layer can determine the information of the target file (indicated by the second descriptor). If the first descriptor exists in the mapping table, it indicates that the current close operation is targeting a valid file descriptor managed by the security management layer.
[0032] Once the security descriptor is confirmed to exist in the descriptor map table, this step is also performed by the security management layer, which operates on both the descriptor map table and the operating system kernel. The security management layer first unlocks and removes the entry associated with the first descriptor from the map table. This is to prevent subsequent threads from referencing a closed descriptor when operating on the file. After confirming that no other thread holds a reference to the security descriptor, the security management layer uses the second descriptor (real_fd) to call the operating system's `close` function to truly close the file. This is the actual resource release operation, handled by the operating system kernel.
[0033] Disk read and write operations typically occur within the server's storage subsystem. The disk array 106 can be an internal server hard drive, SSD (solid-state drive), or network storage device (such as storage connected via SATA, SAS, or NVMe interfaces), or an external storage resource accessed via network 104, such as a NAS (network attached storage) or SAN (storage area network) device.
[0034] Internally, disk read / write requests are initially generated by the Central Processing Unit (CPU) or an application (running on the CPU). When a process or thread needs to read or write a file on the disk, it issues a request by invoking system calls provided by the operating system. These system calls include, but are not limited to, read, write, open, and close; they are essentially a series of instructions executed by the application or thread via the CPU. Once a system call is triggered, the request is passed to the operating system kernel, a core component of the server software architecture responsible for managing hardware resources and providing high-level system services. Upon receiving the disk read / write request, the kernel further processes it and sends it to the storage device driver. This driver, part of the kernel, is responsible for communicating with specific storage hardware, including disks, SSDs, or network storage devices. The storage device driver, upon receiving the request, translates the read / write operation into commands that directly interact with the storage hardware, sending them to the storage device via a hardware interface (such as SATA, SAS, or NVMe) to perform the actual data read or write operation. After completion, the storage device returns the result to the driver, which then passes the result or status back to the kernel, which ultimately returns the response to the application or thread that initially initiated the request.
[0035] The embodiments of this application provide a multi-threaded file management method. Figure 2 This is a flowchart of an optional multi-threaded file management method according to an embodiment of this application; as follows: Figure 2 As shown, this multi-threaded file management method includes:
[0036] Step S202: Receive a first instruction sent by the first thread, wherein the first instruction is used to instruct the target file to be closed, and the first instruction includes a first descriptor;
[0037] It's important to note that the first instruction refers to an operation request initiated by a thread within the application or system; in this case, it's an instruction to close a target file. In practice, this typically manifests as a call to a function like `safe_close`, where the parameter includes the security descriptor of the file to be closed. The target file refers to a specific file in the system that is being accessed or manipulated, identified by its corresponding first descriptor (security descriptor).
[0038] The first file descriptor refers to the security descriptor (safe_fd), which is an additional layer of descriptors created by the system for more secure file descriptor management. The value of a security descriptor is typically much higher than the system's default file descriptor range to avoid conflicts with system-level descriptors.
[0039] The system receives a command to close a target file, which includes a security descriptor as a parameter. This means that when a thread or process in the system wants to close a file, it does not directly operate on the system-level file descriptor, but instead conveys the close request through a higher-level, more secure descriptor (the security descriptor). This approach increases the security and accuracy of the close operation because the security descriptor has better control and management over the file descriptor's lifecycle.
[0040] In multithreaded or concurrent environments, the safety and reliability of resource management (such as file descriptors) are crucial to avoid problems such as data corruption, resource leaks, or security vulnerabilities. To address this, a file management mechanism based on security descriptors can be designed. When a thread or process wants to close a file, it sends a close command (the first command), which carries a security descriptor instead of the direct file descriptor. Upon receiving this close request, the system uses the security descriptor to look up the relevant file descriptor mapping table, thereby finding the actual file descriptor that needs to be closed, ensuring that the correct target file is closed.
[0041] The first file descriptor starts with a high value (such as 10000 or higher), which does not overlap with the value range of file descriptors (real_fd or fd for short) in traditional operating systems (usually 0 to FD_SETSIZE, with a default value of 1024, but can be larger in practice), thus ensuring the independence and security of the two.
[0042] Because security descriptors start at a much higher level than file descriptors, this design effectively avoids numerical overlap between the two. At the operating system level, file descriptor management typically targets a lower numerical range, while security descriptors are managed independently in user space, avoiding conflicts between system resource management and user-defined resource management.
[0043] Security descriptors are generated using a global atomic counter that increments from a large starting value (e.g., 10000) to ensure that each descriptor is unique across the entire system. Even in high-concurrency scenarios, this mechanism prevents two or more threads / processes from simultaneously acquiring the same descriptor, thus avoiding resource congestion and contention.
[0044] Once a security descriptor is used to close a file or resource, the system immediately removes the associated mapping record from the descriptor mapping table. This means that the security descriptor will no longer be associated with any actual file descriptor, and its value will not be used again to create new mapping entries. This measure avoids the potential security risks and data corruption associated with descriptor reuse. Because there is no numerical overlap between security descriptors and file descriptors, even if two different operations are ultimately assigned the same file descriptor, their security descriptors will still be different. Therefore, even in the case of file descriptor reuse, the isolation and security of operations can be ensured through security descriptors.
[0045] Step S204: Access the descriptor mapping table and find the second descriptor corresponding to the first descriptor. The second descriptor is used to indicate the target file, and the descriptor mapping table is used to store the mapping relationship between the first descriptor and the second descriptor.
[0046] It's important to note that the descriptor mapping table is a data structure maintained within the security management layer. It stores the mapping between security descriptors (first descriptors) and actual file descriptors (second descriptors). When a file is opened, an entry is created in the mapping table, recording the actual file descriptor and its associated security descriptor.
[0047] The second descriptor refers to the actual file descriptor (real_fd), which is allocated by the operating system kernel and directly used for file system calls. In the descriptor mapping table, each security descriptor corresponds to an actual file descriptor.
[0048] Upon receiving an instruction to close a target file, the system needs to access the descriptor mapping table and search for a second descriptor (the actual file descriptor) that matches the first descriptor (security descriptor). Through this mapping, the system can locate the specific file to be closed and then perform the subsequent closing operation.
[0049] In optional implementations, in multi-threaded or concurrent environments, to ensure secure management of file descriptors, whenever a file is opened, the system creates a secure descriptor and associates it with the actual file descriptor in the descriptor mapping table. When a file needs to be closed, the system first receives a close request (first instruction) containing the secure descriptor. After this step, i.e., S204, the system accesses the descriptor mapping table, looks up the mapping entry corresponding to the secure descriptor, and then finds the actual file descriptor (second descriptor). This ensures that the close operation is accurately applied to the target file without affecting other files or resources still in use.
[0050] In an optional implementation, the descriptor map can be a hash table, using secure descriptors as keys and state entry pointers as values. State entries contain information such as the actual file descriptor, reference count, close flag, mutex, and condition variables, like `std::unordered_map`. Since the descriptor map is a shared resource, multiple threads may access it concurrently; therefore, read-write locks are used to control concurrent access. Read locks allow multiple threads to read the map simultaneously, while write locks guarantee exclusivity when modifying the map. The specific locking process will be explained in detail later. If a corresponding secure descriptor is not found in the map, this usually means the target file descriptor has been closed or never existed. In this case, an error code, such as `EBADF`, should be returned, indicating an invalid file descriptor.
[0051] Step S206: If a first descriptor exists in the descriptor mapping table, delete the mapping relationship and close the target file based on the second descriptor.
[0052] It's important to note that when the system successfully finds the corresponding real_fd for safe_fd in the descriptor mapping table, it means the system has confirmed the file to be closed. Next, the system removes this mapping from the table to prevent safe_fd from being misused or confused with other operations in the future. Then, the system will actually perform the file closure operation based on the found real_fd, releasing all resources associated with that file.
[0053] In a multithreaded environment, closing a file is an operation that requires special care because multiple threads may simultaneously hold references to the same file. To ensure the safety of the closing operation, when thread A initiates a close command, the system, upon receiving the command, searches for the real file descriptor in the file descriptor mapping table using the `safe_fd`. If a mapping is found, it is immediately deleted. This step is to disconnect the safe file descriptor from the actual file descriptor, preventing future reuse conflicts. Following this, the system will actually close the file and release all related resources, ensuring that no other thread is referencing the `real_fd`. The benefits of this approach are twofold: firstly, it avoids data corruption or security vulnerabilities that can result from file descriptor reuse; secondly, it ensures the proper closing of files in a multithreaded environment, preventing data corruption and other undefined behaviors.
[0054] In an optional implementation, upon receiving a safe close command (safe_close), the system first queries the file descriptor mapping table using the safe_fd to find the corresponding real_fd. If a real_fd is found in the descriptor mapping table, the system immediately removes this mapping to prevent the safe_fd from being mistakenly used for other file operations in the future. Under safe conditions, the system uses the real_fd to execute the actual close system call, closing the file and releasing all related resources. After closing the file, the system also needs to clean up the resources in the state entries associated with the real_fd, such as condition variables and mutexes.
[0055] This application receives a first instruction sent by a first thread, wherein the first instruction is used to instruct the closing of a target file, and the first instruction includes a first descriptor; it accesses a descriptor mapping table to find a second descriptor corresponding to the first descriptor, wherein the second descriptor is used to indicate the target file, and the descriptor mapping table is used to store the mapping relationship between the first descriptor and the second descriptor; if the first descriptor exists in the descriptor mapping table, the mapping relationship is deleted, and the target file is closed based on the second descriptor. By introducing the concepts of a first descriptor (i.e., a security descriptor) and a second descriptor (i.e., the actual file descriptor), the risk of resource conflicts and data corruption can be significantly reduced when multiple threads or threads share resources. When a thread issues a close command (the first instruction), the system first searches the descriptor mapping table for the actual file descriptor associated with the security descriptor, ensuring that only the correct resource is closed. After finding the second descriptor in the descriptor mapping table, the mapping relationship between the first descriptor and the second descriptor is immediately deleted. This means that once a resource is closed, the security descriptor will no longer be mapped to any system resource, preventing descriptor reuse and avoiding threads misusing closed resources. By querying and updating the file descriptor mapping table, the consistency of file resource status is ensured. In a multi-threaded environment, each thread uses an independent security descriptor to reference resources, which helps isolate resource access between threads and avoids errors caused by inconsistent resource states. Therefore, this addresses the technical problem of low security in current file descriptor management methods, thereby improving application security.
[0056] In an optional implementation, closing the target file based on the second descriptor includes: reading the data space corresponding to the first descriptor, wherein the data space is used to indicate the state of the first descriptor; determining the reference count included in the data space, wherein the reference count is used to indicate the number of threads currently accessing the target file; and closing the target file based on the second descriptor if the reference count is a preset number.
[0057] It should be noted that the data space refers to the state entry structure, which is a structure containing information about the file descriptor's state. It stores key information associated with the first descriptor (i.e., the security descriptor), used to indicate and manage the file descriptor's state.
[0058] Reference count is an important field in the data space used to track how many threads or threads are currently using the file descriptor associated with that state entry. Managing the reference count is crucial for ensuring the safe closure of the target file. The preset count refers to a specific value that the reference count needs to reach. During the safe closure of the target file, the actual file closure operation is only performed when the reference count drops to zero (the preset count), ensuring that no other threads or processes are still using the file descriptor.
[0059] It should be noted that the data space, i.e., the state entry structure (fd_entry_t), can contain the following key data:
[0060] real_fd: The actual file descriptor, allocated by the operating system kernel.
[0061] closed: The closing flag, used to indicate whether a file descriptor has been marked as closed.
[0062] ref_count: Atomic reference count used to track the number of threads or processes using this file descriptor.
[0063] lock: Mutex (pthread_mutex_t) provides exclusive access control at the state entry level.
[0064] cond: A condition variable (pthread_cond_t) that allows waiting for the reference count to drop to a preset number.
[0065] creator_pid and creator_tid: Record the process and thread ID that created the file descriptor, which can be used for debugging and auditing.
[0066] create_time: Creation timestamp, used to calculate the lifecycle of a file descriptor.
[0067] When a thread attempts to close a file identified by a security descriptor, the system accesses the state entry (i.e., the data space) corresponding to that security descriptor. The system checks the reference count in the data space, and if the reference count equals a preset number—usually zero—it means that no other thread or process is accessing the file, and therefore it is safe to perform a close operation based on the actual file descriptor (real_fd).
[0068] In an optional implementation, a security descriptor is used as an index to access the descriptor mapping table to retrieve the corresponding state entry. The value of the `ref_count` field is retrieved from the state entry, indicating how many threads or processes are currently using the file descriptor. If the reference count is greater than a preset number (i.e., zero), the thread will wait until the reference count drops to the preset number. This can be achieved using a condition variable, setting the condition variable to wait until `ref_count` drops to zero. Once the reference count reaches the preset number, the system will execute a real `close` system call, closing the file using `real_fd` and releasing all resources associated with the file descriptor. Finally, the state entry is cleaned up, including releasing resources such as mutexes and condition variables contained in the entry. When handling reference counting, atomic operations (such as `atomic_fetch_add` and `atomic_fetch_sub`) are used to ensure that incrementing and decrementing the reference count are thread-safe.
[0069] According to the embodiments described above, when a safe close command is received, the system checks whether the reference count in the status entry is zero. If not, it waits until the reference count reaches zero, setting a close flag during this period. Once the reference count reaches zero, the system actually closes the file and cleans up the resources associated with the status entry. This mechanism, based on atomic operations and condition variables, ensures the safety and consistency of descriptor closure, especially in multi-threaded concurrent environments, avoiding race conditions in close operations and ensuring thread safety and descriptor uniqueness in resource management.
[0070] In an optional implementation, before determining the number of references included in the data space, the method includes: setting the data space corresponding to the first descriptor to a first locked state, wherein the first locked state is used to indicate that the data space is prohibited from being accessed by at least one second thread, and the second thread is not the first thread; setting the close indicator bit included in the data space to a first preset value, wherein the first preset value is used to indicate that the first descriptor is in a closed state;
[0071] After closing the target file based on the second descriptor, the process includes: setting the data space corresponding to the first descriptor to a first unlock state, wherein the first unlock state is used to indicate that the data space can be accessed by a first thread and at least one second thread.
[0072] The first locked state can be a mutex lock state set in the state entry, indicating that the data space is not allowed to be accessed by any thread other than the currently operating thread (the first thread) (the second thread), to ensure data consistency and integrity. The first preset value refers to the flag value of the descriptor closed state, usually 1 or true, used to mark that the file descriptor in the state entry has been closed.
[0073] The first unlocked state indicates that after the file descriptor is safely closed and all references are released, the mutex lock state of the data space will change from locked to unlocked, meaning that other threads can access and use the data space again. However, it should be noted that since the file has been closed, subsequent access may return an error.
[0074] When a thread (the first thread) decides to close a file descriptor, it first sets the data space corresponding to the descriptor (status entry) to a locked state. This prevents other threads (the second thread) from modifying or accessing the data space while the closing operation is in progress. Subsequently, the close indicator bit in the status entry is set to a first preset value, indicating that the file descriptor is in the process of being closed.
[0075] Once the actual file descriptor (the second descriptor) is closed and all references to that file descriptor are released, the data space will be unlocked. This means the data space is once again open to all threads, but because the file descriptor was marked as closed, any subsequent access attempts will be considered illegal and may return an error.
[0076] In an optional implementation, in a multithreaded environment, to ensure the safety of file descriptor closing operations, when a thread decides to close a file descriptor, it first locks the status entry. This is achieved by setting a mutex (such as `pthread_mutex_t`) to a locked state (first locked state), ensuring that the status entry is not modified by other threads during the file closing process. Simultaneously, the close indicator bit in the status entry is set to a first preset value (such as 1), indicating that the file descriptor is in a closed state. Once the file is truly closed and all reference counts are zero, the status entry is unlocked (set to the first unlocked state). However, this does not mean that the file descriptor can be used again, but rather that the data space can be read by other threads, for example, by checking the close indicator bit.
[0077] In an optional implementation, before closing the file descriptor, a mutex is acquired in the status entry to prevent other threads from accessing it. The close indicator in the status entry is set to a first preset value, marking the file descriptor as closed. Waiting using a condition variable continues until the reference count in the status entry becomes 0, ensuring all threads have released their references to the file. Based on the actual file descriptor, the `close` system call is invoked to truly close the file. After the file closing operation is complete and all resources are cleaned up, the previously acquired mutex is released, making the status entry visible to all threads again.
[0078] In the implementation described above, the `safe_close` function first acquires a global write lock to process the mapping table, searching for the `real_fd` corresponding to the `safe_fd`. If a mapping is found, the mapping is removed, and the safe shutdown process continues. Before the actual shutdown operation, the function locks the state entry, sets the close indicator to `true`, and waits for the reference count to reach zero. Once all references are released, the function calls the system call `close` to close the file, unlocks the state entry after the operation is complete, and then releases all associated resources. If no entry is found in the mapping table, the system `close` function is called directly, but it may return an error indicating that `safe_fd` is invalid or the file has been closed. In this way, the system can ensure that the file descriptor shutdown operation is safe in a multi-threaded environment, and that the management of state entries is thread-safe.
[0079] In an optional implementation, before accessing the descriptor mapping table, the method includes: setting the descriptor mapping table to a second locked state, wherein the second locked state is used to indicate that the descriptor mapping table is prohibited from access by at least one second thread; after deleting the mapping relationship, the method includes: setting the descriptor mapping table to a second unlocked state, wherein the second unlocked state is used to indicate that the descriptor mapping table can be accessed by a first thread and at least one second thread.
[0080] It should be noted that the second locked state can be a state in which the descriptor mapping table is not allowed to be accessed or modified by any thread other than the thread currently performing the locking operation (i.e., the first thread). The second unlocked state can be a state in which the descriptor mapping table is allowed to be accessed and modified by all threads, including the first thread and any other thread (at least one second thread).
[0081] Before accessing the descriptor mapping table, the system sets it to a second locked state. This ensures that the mapping table cannot be accessed by other threads, thus avoiding potential concurrency conflicts when reading or modifying the mapping table. After deleting a mapping relationship from the descriptor mapping table, the system sets it back to the second unlocked state, allowing all threads (including the first and at least one second thread) to access and modify the mapping table again, ensuring resource sharing and synchronization in a multi-threaded environment.
[0082] In multithreaded programs, access to shared resources must be properly synchronized to avoid race conditions and data inconsistencies. As a global data structure, the descriptor map needs to be protected using locking mechanisms during access and modification to ensure thread safety. Access to and modification of the descriptor map uses read-write locks (pthread_rwlock), which allows multiple threads to access the map concurrently (read state) but requires exclusive access (write state) when modifying the map (such as insertion or deletion).
[0083] In an optional implementation, before accessing the descriptor mapping table for modification (such as deleting mappings), the system acquires a write lock (pthread_rwlock_wrlock) on the descriptor mapping table, setting the mapping table to a second locked state, disallowing any other thread from accessing or modifying it until the lock is released. After the write lock is acquired, the mapping table is in the second locked state, at which point the deletion of mappings can be safely performed. After the modification operation is completed, the system releases the write lock (pthread_rwlock_unlock), setting the descriptor mapping table back to the second unlocked state, allowing other threads (including the first and at least one second thread) to access and modify the mapping table again.
[0084] For example, thread A first acquires a write lock on the global descriptor map using `pthread_rwlock_wrlock`, setting the descriptor map to the second locked state, preventing any other thread from accessing it. Then, thread A searches the map for the mapping corresponding to the safe descriptor `safe_fd=10001`, and if it exists, deletes the mapping. Finally, it releases the write lock using `pthread_rwlock_unlock`, setting the descriptor map back to the second unlocked state, allowing other threads to continue accessing the map.
[0085] Through the above-described embodiments of this application, the security of accessing and modifying the descriptor mapping table in a multi-threaded concurrent environment is ensured by a global lock mechanism, effectively avoiding data inconsistency and race conditions, and improving the security management of file descriptors and the overall stability of the multi-threaded system.
[0086] It should be noted that the descriptor mapping table is a global mapping table that stores all security descriptors and their corresponding status entries. These status entries contain information such as the actual file descriptor, reference count, and closed status.
[0087] `static pthread_rwlock_t global_table_lock` is a read-write lock used to protect access to a global table, ensuring that read and write operations (such as insertion, search, and removal) on the table are thread-safe in a concurrent environment. Read-write locks allow multiple threads to perform read operations simultaneously, but only one thread is allowed to perform write operations at a time. This design can improve the performance and responsiveness of multithreaded applications.
[0088] static std::unordered_map<int,fd_entry_t> `fd_table` is an unordered hash map using the `std::unordered_map` container from the C++ standard library. It uses security descriptors as keys and pointers to state entry structures as values. This data structure provides fast lookup and insertion capabilities, making it ideal for dynamically managing the mapping of large numbers of file descriptors, especially performing exceptionally well in high-concurrency environments. It offers average constant-time lookup performance, making it ideal for implementing fast descriptor mapping lookups. In this map, `safe_fd` serves as the key, and pointers to `fd_entry_t` (state entries) serve as the values. This design allows the system to quickly locate the state information of the actual file descriptor corresponding to a given security descriptor, thereby efficiently intercepting and verifying file operations.
[0089] `static atomic_uint next_safe_fd=10000` is an atomic variable used to generate the next available safe descriptor. Atomic variables ensure that the generation of safe descriptors is thread-safe in high-concurrency environments, avoiding numerical conflicts. The initial value of a safe descriptor is typically set to a value much larger than the system default descriptor range (e.g., 10000). This effectively distinguishes the system-level file descriptor space from the user-level safe descriptor space, preventing accidental operations and reuse conflicts. `next_safe_fd` is used to generate the next available safe descriptor, and its initial value is set to 10000, much larger than the system default descriptor range, to avoid conflicts with system-level descriptors. Each time a new safe descriptor is generated, the value of `next_safe_fd` is atomically incremented, ensuring that each generated safe descriptor is globally unique.
[0090] Example 1:
[0091] Figure 3 This is a schematic diagram of an optional safety shutdown process according to an embodiment of this application; as shown Figure 3As shown, after the first thread 302 completes access to the target file, step S302 can be executed to send a first instruction to the security management layer 304. Upon receiving the first instruction, the security management layer 304 can execute steps S304-S306 to access the descriptor mapping table and, if the conditions are met, delete the mapping relationship of the first descriptor. Then, step S308 is executed to send a close instruction to the kernel layer 306. The first instruction can be, for example, safe_close(10001), and the close instruction can be sys_close(5), where 10001 can be the first descriptor and 5 can be the second descriptor.
[0092] Specifically, the application has successfully opened and used a file, obtaining a security descriptor `safe_fd`. A global state tracking table has been created and maintained, recording the state of all security descriptors, including reference counts, close flags, creator information, etc.
[0093] Suppose thread ThreadA finishes its operations on a file and decides to close it. ThreadA calls the safe close interface provided by the security management layer, such as the `safe_close` function, passing the safe file descriptor `safe_fd` to the interface. Upon receiving ThreadA's close request, the security management layer begins executing the safe close protocol. The security management layer looks up the real file descriptor `real_fd` associated with `safe_fd` in the global file descriptor mapping table. The security management layer checks the status of `safe_fd` to confirm whether it has been closed. If `safe_fd` is already marked as closed, it directly returns an error notification to ThreadA. If the status of `safe_fd` indicates that the file has not yet been closed, the security management layer sets the descriptor's status to "closing". Simultaneously, it uses atomic operations to decrement the descriptor's reference count. The security management layer monitors the reference count using a condition variable. If the reference count is greater than zero, it means that other threads are still holding the descriptor, and the system will wait until all threads release their references to `safe_fd`. Once all references are released, i.e., the reference count reaches zero, the security management layer removes the entry associated with `safe_fd` from the global mapping table to prevent potential multiple closes in the future. The security management layer invokes the system-level `close` system call to close the `real_fd` associated with `safe_fd`, releasing operating system-level resources. After `real_fd` is successfully closed, the security management layer destroys the state entry associated with `safe_fd`, releasing memory resources used for state management. Finally, the security management layer notifies ThreadA, which issued the close request, that the file descriptor `safe_fd` has been safely closed. At this point, ThreadA can continue executing subsequent operations or terminate the thread.
[0094] If `safe_fd` does not exist in the global file descriptor table (e.g., it is closed or has never been opened), the security management layer will directly return an error code, such as EBADF (Bad File Descriptor), to the application without performing any further closing operations or resource release. While waiting for the reference count to reach zero, if the waiting time exceeds a preset timeout threshold, the security management layer will trigger a timeout handling mechanism, log the event, and attempt to take recovery measures, such as forcibly closing `real_fd`, to avoid a possible deadlock.
[0095] The safe shutdown process ensures the safety and consistency of file descriptor operations in a multi-threaded environment, preventing accidental data corruption, resource conflicts, and security vulnerabilities caused by concurrent operations. This process implements lifecycle management of descriptors through a safe descriptor management system. In particular, through reference counting and condition variable mechanisms, it ensures that all threads have correctly released their references before the descriptor is truly closed, thereby improving the stability and security of server applications.
[0096] In an optional implementation, before receiving the first instruction sent by the first thread, the process includes: receiving a second instruction sent by the third thread, wherein the second instruction is used to instruct the opening of the target file, wherein the third thread and the first thread belong to the same process space; generating a first descriptor and a second descriptor; establishing a mapping relationship between the first descriptor and the second descriptor; accessing the descriptor mapping table and storing the mapping relationship in the descriptor mapping table.
[0097] It should be noted that the second instruction is issued by a third thread (usually another thread in the process space of the first thread), and is used to instruct the opening of a new file or resource, thereby generating a new file descriptor. Process space refers to the address space within a process, where multiple threads share memory resources and descriptor mapping tables.
[0098] Before receiving the first instruction from the first thread, the system may first receive a second instruction from a third thread. This third thread actually belongs to the same process space; that is, it could be another thread within the first thread, or a thread within the same process. The goal of the second instruction is to open the target file. This action causes the system to generate a first descriptor and a second descriptor—a security descriptor and an actual file descriptor. Subsequently, the system establishes a mapping relationship between the first and second descriptors to ensure their association. Finally, the system accesses the descriptor mapping table and stores the mapping relationship therein.
[0099] In an optional implementation, when a third thread requests to open a file, the system receives and parses the open instruction, which typically includes parameters such as the specified filename and open mode. The system calls a kernel interface, such as `sys_open`, to request the generation of an actual file descriptor (`real_fd`). The system uses the atomic variable `next_safe_fd` to generate a safe descriptor (`safe_fd`), ensuring its value is much larger than the system's default descriptor range to prevent overlap. A state entry structure is created, recording `real_fd`, the initial reference count (usually 1), the close flag (initially not closed), and necessary locking mechanisms and condition variables. A write lock on the global descriptor mapping table is acquired, and the newly created state entry (containing `real_fd` and related state information) is mapped to `safe_fd` and stored in the descriptor mapping table. After releasing the write lock, the mapping relationship can be safely used in a multi-threaded environment. The generated safe descriptor (`safe_fd`) is returned to the third thread for subsequent file operations.
[0100] Through the above-described implementation of this application, when a thread issues an open file command, the system generates a security descriptor and an actual file descriptor, creates a status entry, and then securely establishes the mapping relationship between the two in a global descriptor mapping table. This approach ensures the security and consistency of file descriptor management and operations in a multi-threaded environment, providing a reliable infrastructure for subsequent file read, write, and close operations.
[0101] In an optional implementation, before accessing the descriptor mapping table, the method includes: setting the descriptor mapping table to a third locked state, wherein the third locked state is used to indicate that the descriptor mapping table is prohibited from access by at least one fourth thread, the fourth thread being a non-third thread;
[0102] After storing the mapping relationship in the descriptor mapping table, the process includes: setting the descriptor mapping table to a third unlock state, wherein the third unlock state is used to indicate that the descriptor mapping table can be accessed by a third thread and at least one fourth thread.
[0103] It should be noted that the third locking state can be a descriptor mapping table in a locked mode, in which no other thread (at least a fourth thread) other than the current operating thread (the third thread) is allowed to access or modify it, ensuring the integrity and consistency of the data.
[0104] The fourth thread refers to any thread other than the one performing a specific operation (such as storing or deleting a mapping) that may attempt to access the descriptor mapping table simultaneously.
[0105] The third unlock state can be a state of the descriptor mapping table that allows all threads, including the currently operating thread (the third thread) and any other thread (at least one fourth thread), to access and modify the mapping table, restoring normal concurrent operation capabilities.
[0106] Before performing any operation requiring access to the descriptor mapping table, such as storing or deleting mappings, the system sets the descriptor mapping table to a third-locked state to ensure that the mapping table cannot be accessed or modified simultaneously by other threads (a fourth thread) during critical operations. Only after this step is completed can the descriptor mapping table be read and written. Once the storage or deletion operation is complete, the system sets the descriptor mapping table back to the third-unlocked state, restoring all threads' access to the mapping table while maintaining data consistency and thread safety.
[0107] To ensure safe access and modification of the descriptor mapping table in a multi-threaded environment, a read-write lock (pthread_rwlock) is used to control access to the table. The read-write lock design allows multiple threads to access the mapping table during read operations, but during write operations (such as inserting or deleting mappings), only one thread is allowed to acquire the write lock for exclusive access. Thus, before each access to the descriptor mapping table, the system acquires the write lock, setting the mapping table to a third-locked state. After completing the modification operation, the system releases the write lock, restoring the mapping table to a third-unlocked state, allowing other threads to continue accessing it.
[0108] In an optional implementation, before performing any operation that requires modifying the descriptor map (such as storing or deleting mappings), a global write lock is first acquired using `pthread_rwlock_wrlock`, setting the descriptor map to a third-locked state. This ensures that no other thread can access or modify the map during the operation. After acquiring the lock, the descriptor map is in a third-locked state, at which point it is safe to perform operations that modify the map, such as inserting new entries, storing mappings in the map, or removing closed descriptor entries from the map. After completing the map modification operation, the previously acquired write lock is released using `pthread_rwlock_unlock`, setting the descriptor map back to the third-unlocked state, allowing all threads, including the third thread and all other threads, to re-access the map.
[0109] Through the above-described implementation of this application, the `safe_descriptor_operation` function acquires a global write lock using `pthread_rwlock_wrlock` before inserting or deleting mapping relationships, setting the descriptor mapping table to a third-locked state to prevent other threads from accessing it. After completing the mapping table operation, it releases the write lock using `pthread_rwlock_unlock`, restoring the mapping table to a third-unlocked state, allowing all threads to access the mapping table again. This method ensures the thread safety and data consistency of the descriptor mapping table in a multi-threaded environment and is an important component of this invention for implementing secure file descriptor management.
[0110] Example 2:
[0111] Figure 4 This is a schematic diagram of an optional secure opening process according to an embodiment of this application; as shown... Figure 4 As shown, when the third thread 402 in the system wants to open a file, step S402 can be executed to send a second instruction to the security management layer 304. The security management layer 304 can then execute step S404 to send an open instruction to the kernel layer 306. The second instruction can be `safe_open("file.txt")`, which carries information indicating the target file name, and the open instruction can be `sys_open("file.txt")`. Then, after the kernel layer 306 generates the second file descriptor, it executes step S406 to send the second file descriptor to the security management layer 304. The security management layer 304 can then execute steps S408 and S410 to generate a first file descriptor and establish a mapping relationship between the first and second file descriptors. Afterwards, step S412 is executed to send the first file descriptor to the third thread 402.
[0112] Specifically, the application starts on a server, which could be a web server, database management system, or other high-performance server software. In this case, the application does not directly interact with the operating system kernel for file operations; instead, it does so through a wrapped security library interface. Suppose a thread in the application (let's call it thread A) plans to open a file for read and write operations, it will send a file open request to the security management layer. This request includes the file path, access mode (such as read-only or read-write), and other necessary parameters.
[0113] After receiving a request from thread A, the security management layer first performs a series of preprocessing steps, including verifying that thread A is authorized to perform such operations and ensuring that the request is in the correct format. Following preprocessing, the security management layer invokes the operating system kernel's `open` system call. This step is handled by the kernel, which allocates a real file descriptor (`real_fd`) within the standard system descriptor space (e.g., 0-1024) and associates it with the opened file.
[0114] After the kernel returns the `real_fd`, the security management layer immediately generates a unique security descriptor (`safe_fd`) from a predefined security descriptor space (e.g., starting from 10000). This security descriptor replaces the directly used real descriptor to isolate and protect file descriptor management. Next, the security management layer creates a state entry to track the state of the `real_fd` associated with the `safe_fd`. The state entry contains key information such as: the `real_fd` value, a close flag (initially set to not closed), a reference count (initialized to 0), a thread mutex, a condition variable, the creator's PID and TID, and a creation timestamp. The security management layer then associates the generated `safe_fd` with its corresponding state entry, storing this information in a global mapping table. This mapping table maintains a one-to-one relationship between `safe_fd`s and state entries, ensuring that each security descriptor has a clear state tracker. Before allocating a `safe_fd` in the mapping table, the security management layer performs an atomicity check to ensure that no other thread is requesting the same or a similar `safe_fd`. If the check passes, `safe_fd` will be officially allocated to thread A and inserted into the mapping table; otherwise, an attempt will be made to generate a new safe descriptor until allocation is successful. Using a global write lock, the security management layer updates its maintained mapping table, adding a record pointing from `safe_fd` to the state entry. This way, in subsequent file operations, threads can quickly access the associated state entry and the actual descriptor through the safe descriptor.
[0115] Once the mapping is established, the security management layer releases the global write lock and returns the `safe_fd` to thread A. Thread A can now use this safe descriptor for file system calls, such as reading and writing, without worrying about resource conflicts or data corruption with other threads. Before actually performing file read / write operations, all file system calls by thread A are intercepted by the security library. The security library performs pre-verification of `safe_fd`, checking the close flag and reference count in its status entry to ensure the validity and security of the file descriptor. If the `safe_fd` verification passes, the security management layer will invoke the kernel's system call to perform the actual file operation. Regardless of whether it's a read, write, or other operation, the reference count of the status entry is incremented before each operation and decremented after the operation, thereby monitoring and controlling the descriptor's usage.
[0116] The entire secure open process emphasizes the core role of the security management layer in isolating the file descriptor space, maintaining state entries, and performing atomic operations. By generating secure descriptors, creating state entries, and updating the global mapping table, it ensures that thread A can safely interact with a specific file, while also preventing other threads from accidentally accessing or modifying this resource, greatly improving the security and reliability of file descriptor management in a multi-threaded environment.
[0117] It's important to note that when a process or thread first obtains a file descriptor (system_fd or simply fd) through a system call such as open, the next step is to generate a safe descriptor (safe_fd) and create a state entry (i.e., a data space) based on it to track and manage the safety state of that file descriptor. The process of generating the safe descriptor and state entry and inserting them into the mapping table is thread-safe to avoid descriptor reuse conflicts and ensure the uniqueness of each pair of system_fd and safe_fd mappings.
[0118] Each time a `system_fd` is allocated, the application calls an internal function to create a `safe_fd`. This `safe_fd` starts at 10000, significantly higher than the system's default descriptor range (0-1023), to provide an isolated descriptor space. After creating the `safe_fd`, the application creates a status entry containing information such as the `system_fd`, reference count, and closed status flags, used for subsequent file operation interception and verification. Once created, the entry is inserted into the global descriptor map (i.e., the descriptor map), using `safe_fd` as the key and the entry pointer as the value. This allows subsequent file operations to access the map via the `safe_fd` and find the corresponding entry for status verification.
[0119] To avoid potential conflicts in reusing safe_fds during high-concurrency scenarios, after a safe_fd is allocated, it is first checked whether it already exists in the global mapping table. If the safe_fd already exists, it means that the safe descriptor has been used. In this case, the system will re-allocate a new safe_fd until an unused safe_fd is found, thus ensuring the uniqueness of each safe_fd.
[0120] To avoid excessive attempts and checks when requesting a safe_fd, a request count limit is introduced. The specific strategy is as follows: when an application attempts to generate a safe_fd, the number of requests is limited, for example, to 100. If no usable safe_fd is found within 100 attempts, it indicates that the global mapping table may be full or the system is in an abnormal state, requiring further processing. To further optimize the request process, this invention employs a penalty mechanism: after the initial failure, the value incremented from the safe descriptor's starting point (10000) gradually increases with each subsequent safe_fd request. For example, it increases by 1 after the first failure, 10 after the second, 100 after the third, and so on. This incremental increment prevents excessive attempts at adjacent values in the descriptor space, reduces conflicts during the request process, and improves request efficiency.
[0121] In an optional implementation, suppose the thread ThreadOmega attempts to generate a safe descriptor `safe_fd`. The thread first obtains a `system_fd` of size 4 via a system call. Then, the thread calls the internal `safe_fd_generation` function, whose execution flow is as follows:
[0122] The `safe_fd_generation` function attempts to generate a `safe_fd`. First, it checks `next_safe_fd`. Assuming its current value is 10000, `safe_fd=10000` becomes a candidate value. The function then checks the global mapping table. If `safe_fd=10000` is already mapped, the allocation of the `safe_fd` is considered a failure. After the first failed allocation, `next_safe_fd` is adjusted to 10001 (i.e., 10000 + 1). It attempts to generate a `safe_fd` again. If `safe_fd=10001` is also already mapped, `next_safe_fd` is adjusted to 10011 (i.e., 10001 + 10), and so on, until an unmapped `safe_fd` is found. Once a new, unused `safe_fd` is identified, the `safe_fd_generation` function creates a state entry, initializing its fields, such as setting `real_fd` to `system_fd=4`, `closed` to `false`, `ref_count` to 1, etc. Finally, the entry will be inserted into the global mapping table with safe_fd as the key and the address of the entry as the value.
[0123] In an optional implementation, after storing the mapping relationship in the descriptor mapping table, the process includes: receiving a third instruction sent by a fifth thread, wherein the third instruction is used to instruct reading data from a target file or writing data to a target file, the third instruction includes a first descriptor, and the fifth thread and the first thread belong to the same process space; accessing the descriptor mapping table and searching for a second descriptor corresponding to the first descriptor; if the first descriptor exists in the descriptor mapping table, reading the data space corresponding to the first descriptor and incrementing the reference count included in the data space by one; performing the read or write operation indicated by the third instruction on the target file; and decrementing the reference count included in the data space by one.
[0124] It should be noted that the third instruction refers to a request to read or write a file, such as one issued through the `safe_read` or `safe_write` functions, which includes a safety descriptor (`safe_fd`) as a parameter. The fifth thread refers to a thread that belongs to the same process space as the first thread (possibly the thread that issued the close instruction), and it sends the third instruction to perform file operations.
[0125] Before performing file operations (such as reading or writing), the fifth thread sends a third instruction, passing the safe file descriptor (safe_fd) contained within the instruction to the system. The system then accesses the descriptor mapping table to find the actual file descriptor (real_fd) corresponding to safe_fd. If the first descriptor exists in the mapping table, the system reads the corresponding status entry for that descriptor and increments the reference count in the status entry to ensure the safety of the operation. After the file operation is complete, the system decrements the reference count. When the reference count becomes zero, it indicates that all operations on the file have ended, and the file can be safely closed.
[0126] In an optional implementation, a mechanism for safe access and manipulation of file descriptors in a multi-threaded environment is provided. When a fifth thread needs to read or write to a target file, it initiates a request using a safe descriptor (first descriptor). The system checks the descriptor mapping table to confirm the existence of an actual file descriptor (second descriptor) associated with the safe descriptor. If it exists, the system atomically increments the reference count in the descriptor's state entry to ensure the current operation is thread-safe. After the file operation is complete, the reference count is atomically decremented to track the descriptor's usage status and ensure that the descriptor can be safely closed after all references have expired, preventing descriptor reuse conflicts and the use of closed descriptors.
[0127] The fifth thread sends a read or write request containing the `safe_fd`. The system accesses the descriptor mapping table to find the corresponding `real_fd` and state entry for `safe_fd`. If the mapping exists, the system locks the state entry (using a mutex) and then atomically increments the reference count. The actual read or write operation is performed using the `real_fd`, while `safe_fd` is only used for mapping and state verification. After the operation is complete, the reference count is decremented. If the reference count reaches zero and the descriptor is closed, the resources associated with the descriptor can be released.
[0128] Through the above-described embodiments of this application, in a multi-threaded environment, secure file descriptor read operations are achieved using secure descriptors and descriptor mapping tables, combined with reference counting and locking mechanisms. When handling write operations, the process is essentially the same, except that the underlying system function called changes from `read` to `write`. This mechanism ensures the safety, consistency, and correctness of file descriptors in a multi-threaded environment, preventing errors and data corruption that may occur during concurrent multi-threaded operations.
[0129] In an optional implementation, incrementing the reference count of the data space includes: setting the data space corresponding to the first descriptor to a fourth locked state, wherein the fourth locked state is used to indicate that the data space is prohibited from being accessed by at least one sixth thread, and the sixth thread is not the fifth thread; incrementing the reference count of the data space; and setting the data space corresponding to the first descriptor to a fourth unlocked state, wherein the fourth unlocked state is used to indicate that the data space can be accessed by the fifth thread and at least one sixth thread.
[0130] Decrement the reference count of the data space by one, including: setting the data space corresponding to the first descriptor to the fourth locked state; decrementing the reference count of the data space by one; and setting the data space corresponding to the first descriptor to the fourth unlocked state.
[0131] It should be noted that the fourth locking state is used to indicate that the current thread (the fifth thread) is modifying the reference count in the data space. At this time, the data space is not allowed to be accessed or modified by threads including but not limited to the sixth thread (any thread other than the fifth thread), in order to ensure the atomicity and integrity of the operation.
[0132] The fifth thread can be a thread that is currently incrementing or decrementing the reference count; in this case, the fifth thread actually refers to the current thread that is calling the safe file operation interface. The sixth thread refers to any thread that is not currently performing a reference counting operation, i.e., any thread other than the fifth thread.
[0133] When performing file read and write operations, the system locks the data space to increment the reference count. This process ensures that modifications to the reference count are not interfered with by other threads, thus maintaining data consistency. Similarly, when the operation is complete and the reference count needs to be decremented, the system also locks the data space to prevent multiple threads from modifying the reference count simultaneously, which could cause data corruption.
[0134] When locking the data space, the system sets it to the fourth locked state, allowing only the currently operating thread (the fifth thread) to access and modify the reference count, effectively preventing interference from other threads (the sixth thread). After modifying the reference count, the system restores the data space to the fourth unlocked state, allowing other threads to access the data space again and restoring normal concurrent operations.
[0135] In an optional implementation, taking a safe read operation as an example, when a thread (the fifth thread) attempts to read a file through the safe descriptor `safe_fd=10001`, the system first increments the reference count by 10001 by calling `increment_reference_count(10001)`. The system first acquires the mutex corresponding to `safe_fd=10001`, setting the data space to the fourth locked state. In the locked state, the system checks and atomically increments the reference count. This operation ensures that even if multiple threads attempt to read simultaneously, the reference count will not be incorrect. After completing the reference counting operation, the system releases the mutex, setting the data space to the fourth unlocked state. This allows other threads to also check and modify the reference count. When the read operation is complete, the system calls `decrement_reference_count(10001)` to decrement the reference count. The steps involved are essentially the same, but in the opposite direction: transitioning from the fourth locked state to the fourth unlocked state, atomically decrementing the reference count, and potentially performing additional cleanup work when the reference count reaches zero.
[0136] The above-described embodiments of this application ensure the atomicity of reference counting operations in file descriptor state entries within a multi-threaded environment, preventing data races and inconsistencies, and guaranteeing the security and stability of file descriptors and their corresponding operations. Furthermore, by locking and unlocking reference counting operations before and after them, the order and synchronization of multi-threaded access are effectively controlled, improving the overall performance and reliability of the system.
[0137] In an optional implementation, after accessing the descriptor mapping table and finding the second descriptor corresponding to the first descriptor, the method includes: if the first descriptor does not exist in the descriptor mapping table, returning a first prompt message, wherein the first prompt message is used to indicate that the first descriptor is unavailable;
[0138] Setting the data space corresponding to the first descriptor to the fourth locked state includes: determining the value of the close indicator bit included in the data space; and returning a second prompt message when the value of the close indicator bit is a first preset value, wherein the second prompt message is used to indicate that the first descriptor is unavailable.
[0139] It should be noted that the first error message is an error message generated and returned by the system when the corresponding first descriptor cannot be found in the descriptor mapping table. The close indicator bit can be a field in the data space (status entry) used to indicate that the file associated with the first descriptor has been closed. The first preset value usually indicates a closed state, such as the number 1, meaning that the file descriptor has been marked as closed. The second error message is another error message returned by the system if the value of the close indicator bit is the first preset value, indicating that the first descriptor cannot be used for operation.
[0140] Before performing a file descriptor close operation, the system needs to look up the corresponding first descriptor in the descriptor mapping table. If the descriptor is not in the mapping table, the system will return a first message, which is usually an error code such as EBADF, indicating that the descriptor is invalid or expired. If the descriptor exists, the next step is to check the close indicator bit in its data space. If the close indicator bit is set to the first preset value, meaning the file descriptor has been marked as closed, the system will return a second message, also an error indication, stating that the descriptor can no longer be accessed during the closing process.
[0141] To ensure proper closing of file descriptors in a multi-threaded environment, the system employs a multi-level locking and status checking mechanism. First, the system attempts to find the entry corresponding to the safe descriptor in the descriptor mapping table. If not found, it indicates that the descriptor may have been closed by a previous operation or was never validly created, and the system immediately returns an error. If an entry is found, the system further verifies the close indicator status in the entry to confirm whether the safe descriptor has been marked as closed. To ensure the integrity of the data space during this process, the system sets the data space to a fourth locking state during the preparatory phase of the close operation. This is achieved through resources (such as mutexes) in the locking state entries, ensuring that no other thread reads or modifies the data during the close operation, thereby avoiding data races and inconsistency issues.
[0142] In an optional implementation, before attempting to close a file descriptor, the system first checks if a status entry corresponding to the security descriptor exists in the descriptor mapping table. If the first descriptor is not found in the mapping table, the system should immediately return an error code (such as EBADF) indicating that the descriptor cannot be used for operation, typically because the descriptor has already been closed or never allocated. If the first descriptor does exist in the mapping table, the system needs to acquire a mutex lock on the status entry, which is part of setting the data space to a fourth locked state to ensure that the close operation is thread-safe. After the data space is locked, the system checks the close indicator bit in the status entry to confirm whether the first descriptor has been marked as closed. If the value of the close indicator bit is a first preset value (e.g., 1 represents closed), the system returns an error (such as EBADF) indicating that the first descriptor cannot be used because it has been closed; this is the purpose of the second warning message.
[0143] The above-described implementation methods of this application ensure the security and reliability of file descriptor closing operations in a multi-threaded environment. Through strict locking and state verification strategies, the risks of file descriptor state chaos and data corruption caused by concurrent operations are avoided, providing a robust file access management solution for critical systems and high-concurrency services.
[0144] Example 3:
[0145] Figure 5 This is a schematic diagram of an optional secure write process according to an embodiment of this application; as shown... Figure 5 As shown, when the fifth thread 502 wants to write data to a storage device such as a disk, the fifth thread 502 can execute step S502 to send a third instruction to the security management layer 304. Upon receiving the third instruction, the security management layer 304 can execute step S504 to increase the reference count, and then execute step S506 to write data to the interface provided by the kernel layer 306. Afterwards, it executes step S508 to decrease the reference count, and finally executes step S510 to return the result to the fifth thread.
[0146] Specifically, during a secure read process, if any application-layer thread (referred to as "thread A") needs to read data from the disk into the buffer, it will call the encapsulated secure read interface (safe_read) instead of a direct system call. Thread A must provide a secure file descriptor (safe_fd) as a parameter, indicating the file resource it wishes to read.
[0147] Upon receiving a safe read request, the security management layer first attempts to lock a read lock on the global mapping table to access and inspect the status entry. This verifies the validity of `safe_fd`, specifically checking whether the descriptor has been mapped to a real file descriptor (`real_fd`) and whether the file is not closed. Once the read lock is acquired, the security management layer checks the status entry corresponding to `safe_fd`. If the status entry exists and indicates that the file is not closed, the security management layer checks the reference count to confirm that no other thread is attempting to close the file. If everything is normal, the security management layer increments the reference count and then releases the read lock.
[0148] The security management layer then uses `real_fd` to call the kernel's read interface. The kernel reads the data from the disk and places it into the buffer specified by thread A. After a successful read, the security management layer reacquires the mutex lock on the state entry and then atomically decrements the reference count. If the reference count drops to zero and the file is marked as closed, the security management layer notifies the threads waiting to close that they can proceed with the actual close operation. Finally, the security management layer feeds back the read result to thread A and clears all temporary states associated with this read, such as the increased reference count.
[0149] For the safe write process, similar to the initialization steps for safe read, when thread B wants to write data to disk, it will call the safe write interface (safe_write) and provide a safe_fd and the data buffer to be written. Upon receiving the write request, the safety management layer first locks the global file descriptor table, then looks up the status entry corresponding to the safe_fd to verify that the file is open and not closed. Simultaneously, it checks the reference count to ensure that no closing operation is in progress. If the status verification is successful, the safety management layer updates the reference count and then unlocks the file descriptor table. This is to ensure that the file descriptor is not accidentally closed during the write operation.
[0150] The `real_fd` call invokes the operating system kernel's write interface to write data from thread B's buffer to the specified file location on disk. After the write is complete, the security management layer updates the reference count and checks if the file is marked as closed. This check is crucial for preventing write operations to closed files, avoiding data corruption and loss. If the reference count reaches zero and the file is closed, the security management layer notifies threads waiting for file closure via a condition variable, allowing them to perform actual resource release and cleanup operations. The security management layer returns the result of the write operation to thread B, confirming that the data was successfully written to disk, or reporting the reason for the write failure, such as insufficient disk space or permission issues.
[0151] By locking the global mapping table before and after read or write operations, the atomicity and exclusivity of file descriptor operations are ensured, preventing data races and conflicts between multiple threads. The introduction and updating of reference counting, combined with the checking of the close flag in the state entries, guarantees the availability and consistency of file descriptors during read and write operations, avoiding the problem of using closed descriptors. The security management layer can perform additional error checks before and after read and write operations. If an anomaly is detected (such as illegal descriptor access, insufficient permissions, etc.), an error code can be immediately returned to the application thread, preventing potential data corruption and system failures. Through a dynamic anomaly detection engine and state tracking mechanism, file descriptor resources can be monitored and managed more accurately, and unused descriptors can be promptly removed, preventing resource leaks and invalid occupation.
[0152] The secure read / write process employs multi-level checks, inter-thread state synchronization, and conditional wait mechanisms to ensure the safety, consistency, and efficiency of file descriptor operations in a multi-threaded environment. This process not only strengthens the management of file resources but also improves the stability and performance of server applications, especially in scenarios with high concurrency and stringent data integrity requirements.
[0153] The `entry->cond` condition variable is used to wake up a waiting thread when the reference count is zero and the descriptor is marked as closed. This avoids deadlocks or long waits that may occur when attempting to close the descriptor.
[0154] It should be noted that in a multi-threaded environment, the use and management of file descriptors become complex and prone to a series of exceptions, such as using closed descriptors, unauthorized access, and state inconsistencies. To capture and handle these exceptions in real-time operations, a dynamic exception detection engine is introduced. As part of the security management layer, it utilizes a dual mechanism of state machine verification and operation interception to monitor abnormal use of file descriptors.
[0155] In an optional implementation, the use of a closed descriptor can be detected; the anomaly detection engine checks the `closed` flag in the status entry to determine if the descriptor has been marked as closed. If a closed descriptor is detected, the engine immediately returns the error code EBADF to prevent unauthorized access and records the abnormal attempt for subsequent operational auditing.
[0156] In an optional implementation, illegal descriptor access can be detected; when a security descriptor does not exist in the global mapping table, the engine will determine it as illegal access. For illegal security descriptor access, the engine also returns an EBADF error code and logs the exception to prevent illegal operations on unknown or released resources.
[0157] In an optional implementation, state inconsistencies can be detected; the state of the actual descriptor can be checked by calling fcntl F_GETFD to see if it matches the state recorded in the state manager. If a state inconsistency is found, such as a descriptor being closed in the kernel but not marked in the state entry, the engine will mark the state entry as "zombie state" and trigger resource reclamation to prevent system resource leaks and potential instability.
[0158] The core of the anomaly detection engine lies in real-time checking and verification of descriptor states, ensuring pre-operation verification before each file operation and post-operation auditing. The following is an overview of the implementation process:
[0159] Before each safe descriptor operation, the engine accesses the state manager to obtain the descriptor's current state and performs a validity check. At critical operation points (such as descriptor closure and reuse), an atomic state snapshot of the descriptor is taken to ensure state consistency and integrity. After the operation is completed, the descriptor state is checked again to confirm that no abnormal changes have occurred, such as accidental closure or illegal reuse.
[0160] The anomaly detection engine can immediately block unauthorized access, ensuring system consistency and security. Each time an anomaly is detected, the engine records detailed operation context, including operation type, process / thread information, and timestamps, facilitating later problem tracking and analysis. The engine generates anomaly diagnostic reports to help operations and maintenance personnel quickly locate the cause of the problem and take remedial measures.
[0161] It's important to note that deadlock is a common problem in multithreaded applications. It typically occurs when multiple threads are waiting for locks held by each other to be released, resulting in each thread waiting for another, causing the entire system to stall. Using condition variables with timeouts for waiting effectively avoids this problem, ensuring smooth operation and system stability.
[0162] The current time is obtained using the `clock_gettime` function and stored in the `struct timespec ts`, which is the basis for setting timeout waits. The maximum time for a conditional wait is defined by incrementing the number of seconds in `struct timespec ts.tv_sec` by `TIMEOUT_SEC` seconds.
[0163] A thread uses the `pthread_cond_timedwait` function to wait for a condition variable, providing the address of a mutex lock to ensure that the lock cannot be acquired by another thread during the wait, thus avoiding the double-locking problem. This function waits until the condition is met (in this case, the reference count reaches zero) or until a timeout occurs. If `pthread_cond_timedwait` returns the `ETIMEDOUT` error code, it means that the wait has timed out and the condition has not yet been met, indicating a possible deadlock or exception.
[0164] At this point, the system needs to execute an emergency handling procedure, including: calling the `handle_deadlock` function, which analyzes the current lock acquisition situation between threads and attempts to find the root cause of the deadlock; calling the `emergency_close` function to immediately close the actual file descriptor `real_fd` associated with the entry to prevent prolonged resource occupation or potential data corruption; and calling the `generate_diagnostic` function to record the current state and specific information that caused the timeout, including but not limited to thread ID, descriptor ID, and reference count, to facilitate subsequent troubleshooting by maintenance personnel.
[0165] In this code snippet, `entry` refers to a state entry associated with a specific safety descriptor. When a thread attempts to perform a safe shutdown, it checks if the reference count in the `entry` is zero. If no other thread references the descriptor, the thread can safely close it. However, if the reference count is not zero, the thread waits for a specific time period `TIMEOUT_SEC` seconds to allow other threads to complete their operations. If the wait time exceeds the set `TIMEOUT_SEC` seconds (i.e., `result == ETIMEDOUT`), a deadlock or abnormal situation is considered to have occurred. The system calls the deadlock handling function `handle_deadlock`, executes `emergency_close` for a forced shutdown, and generates a diagnostic report via `generate_diagnostic`. This ensures that even in extreme cases, the system can respond promptly and take appropriate recovery measures.
[0166] Figure 6 This is a schematic diagram of an optional multi-threaded file management method according to an embodiment of this application; as shown... Figure 6 As shown, the whole can be divided into application layer 602, security management layer 604 and kernel layer 606. Application layer 602 and kernel layer 606 exist in the existing file access process, while security management layer 604 is unique to the solution of this application. Most of the above-mentioned multi-threaded file management methods are executed in this layer.
[0167] Specifically, the application layer (602) and kernel layer (606) are the core parts of the operating system, responsible for handling low-level management of hardware resources, including thread scheduling, memory management, device drivers, and providing system call interfaces. At this layer, it is crucial to maintain consistency with the original system design, without modifying kernel-level code and logic, to ensure compatibility and stability while avoiding the introduction of new kernel-level bugs or security risks.
[0168] The security management layer 604 creates an intermediate layer to map application-layer requested security descriptors to actual descriptors at the operating system level. This provides an additional layer of protection and management to prevent descriptor-related operational errors. To ensure the safe closing and reuse of file descriptors in a multi-threaded environment, the security management layer maintains a reference count for each descriptor. This allows checking if other threads are using the descriptor before it is actually closed, preventing data corruption and undefined behavior. Before the application layer attempts to perform file operations, the security management layer intercepts these calls and verifies the descriptor's state. It ensures that read and write operations are only allowed when the descriptor is in the appropriate state (e.g., not closed and not reused). To implement descriptor mapping and state tracking, the security management layer maintains a global mapping table where each security descriptor is associated with a state entry. The state entry contains the descriptor's actual value, reference count, close flag, and other relevant metadata such as the creator's PID, TID, and creation timestamp.
[0169] For the security management layer, this can be a zero-intrusion integration system that allows for enhanced file descriptor security without modifying the application source code.
[0170] In an optional implementation, transparent replacement using LD_PRELOAD can be used. This is a Linux-specific feature that allows specific libraries to be dynamically loaded into memory at runtime. By setting LD_PRELOAD=. / libfdguard.so as an environment variable, when the program starts (e.g., . / my_server), system calls such as open, read, write, and close that would normally be invoked at the kernel level will be automatically replaced with corresponding functions from the security management layer, achieving seamless integration of enhanced security features.
[0171] In optional implementations, the APIs provided by the security management layer, such as `safe_open`, `safe_read`, `safe_write`, and `safe_close`, strictly adhere to the parameter lists and function descriptions of the POSIX standard. This means that applications can directly call these APIs, just like calling standard system calls, without requiring additional learning or modification. Whether preloading via `LD_PRELOAD` or directly calling the security management layer's APIs, no modification to the application's source code is needed; only the method for loading the security library needs to be configured. This greatly facilitates applications in enhancing the security of their file descriptor operations without interrupting existing functionality.
[0172] Example 4:
[0173] Figure 7 This is a schematic diagram of another optional multi-threaded file management according to an embodiment of this application; as shown Figure 7 As shown, the seventh thread 702 can execute step S702, sending the fourth instruction. The fourth instruction can be an instruction to close the corresponding file. Refer to the above for the specific safe closing process. The fourth instruction can be `safe_close(10001)`, where 10001 is the first descriptor. After receiving the fourth instruction, the security management layer 304 can access the descriptor mapping table. If 10001 exists, it executes step S704, removing the mapping relationship of the first descriptor (10001). If the eighth thread 704 subsequently closes the file, it executes step S706, sending the fifth instruction, which can be `safe_close(10001)`. The security management layer 304 executes step S708, accessing the descriptor mapping table to search for the mapping relationship of the first descriptor. Since the mapping relationship has been removed in S704, the first descriptor (10001) cannot be found. It then executes step S710, returning the result. The eighth thread 704 can directly execute the close operation `close(10001)`, returning an error indication.
[0174] Example 5:
[0175] In cases of descriptor reuse conflicts, the method described in this application can be used to avoid them. Specifically, for example, if there is a mapping relationship between the first descriptor 10001 and the second descriptor 5, with the second descriptor 5 pointing to file A, thread A can access file A through the first descriptor 10001. At this time, thread B may send a safe close instruction `safe_close(10001)`, closing file A and removing the first descriptor 10001. Simultaneously, the mapping relationship between the second descriptor 5 and file A is also released.
[0176] Subsequently, thread C opens file B. File B may establish a correspondence with second descriptor 5 and obtain first descriptor 10002, establishing a mapping relationship between first descriptor 10002 and second descriptor 5. If thread A is unaware that file A has been closed and still intends to use file A, thread A accesses the kernel interface through first descriptor 10001. However, the security management layer does not find first descriptor 10001, so it returns an error message to thread A.
[0177] In optional implementations, the management of the original security descriptor (safe_fd) lifecycle can be improved, while an intelligent diagnostic system can be introduced to automatically identify and handle potential system anomalies and security vulnerabilities.
[0178] By leveraging machine learning algorithms to analyze historical operation patterns and file descriptor usage frequency, the system predicts future operational trends and provides early warnings of potential descriptor conflicts, leaks, or misuse risks. Building upon the dynamic anomaly detection engine, it adds in-depth analysis of the operation context, such as file type, frequency and pattern of operation requests, and thread attributes related to the operation (e.g., priority, suspension status). When an anomaly is detected, it not only logs the findings but also attempts to automatically restore the system state, such as restarting affected services or reallocating resources.
[0179] The global mapping table is periodically scanned to identify unused security descriptors and their associated resources (such as unclosed file descriptors), automatically triggering secure closure protocols to prevent resource leaks. Security descriptors can be transferred between different threads by creating a shared descriptor mapping data structure and introducing a descriptor ownership exchange mechanism to ensure data security and consistency when transferring file descriptors between threads. The state entries for security descriptors are expanded to include fine-grained access control information, such as read, write, and execute permissions, as well as thread-specific access permissions. Illegal or unauthorized file descriptor operations are filtered through a permission checking mechanism.
[0180] In an optional implementation, metadata such as usage frequency, operation type, and operation time of each security descriptor is continuously monitored and stored in a dedicated historical data storage area. A supervised learning method is used to train a model to predict descriptor usage patterns and potential conflict risks. When the model predicts a high-risk operational trend, an early warning signal is sent to the application layer, suggesting proactive actions such as delaying certain operations or prioritizing critical tasks.
[0181] When a suspected abnormal operation is detected, the anomaly detection engine not only examines the status entries but also delves into the operational context to assess the severity and scope of the anomaly. Based on the type of anomaly and contextual information, it intelligently decides whether and how to perform recovery operations, such as automatically rolling back to the previous stable state, restarting the service, or reallocating resources.
[0182] Add read, write, execute, and thread-specific permission fields to the status entries. Before each descriptor operation, in addition to checking the closed state and reference count, the operator's permissions are also verified, further enhancing system security.
[0183] Suppose a high-concurrency database server application needs to share file descriptors across multiple service threads to access database files. When a thread needs to transfer file descriptor permissions to another thread, not only can resource migration be performed safely, but the access permissions of the file descriptors are also properly managed and controlled before and after the migration. Simultaneously, the system automatically detects and warns of abnormal descriptor usage patterns, such as continuous high-frequency reads and writes, and adjusts resource allocation strategies in a timely manner to avoid potential system crashes or service interruptions. Upon detecting resource leaks, the intelligent diagnostic system automatically reclaims the relevant resources, preventing memory leaks and excessive consumption of file system resources, thus maintaining the long-term stable operation of the system.
[0184] Through the above description of the embodiments, those skilled in the art can clearly understand that the methods according to the above embodiments can be implemented by means of software plus necessary general-purpose hardware platforms. Of course, they can also be implemented by hardware, but in many cases the former is a better implementation method.
[0185] Embodiments of this application also provide a multi-threaded file management device. Figure 8 This is a structural block diagram of an optional multi-threaded file management device according to an embodiment of this application, such as... Figure 8 As shown, the device includes:
[0186] The first receiving module 802 is used to receive a first instruction sent by the first thread, wherein the first instruction is used to instruct the target file to be closed, and the first instruction includes a first descriptor;
[0187] The lookup module 804 is used to access the descriptor mapping table and look up the second descriptor corresponding to the first descriptor. The second descriptor is used to indicate the target file, and the descriptor mapping table is used to store the mapping relationship between the first descriptor and the second descriptor.
[0188] The mapping table adjustment module 806 is used to delete the mapping relationship and close the target file based on the second descriptor if the first descriptor exists in the descriptor mapping table.
[0189] Optionally, the mapping table adjustment module 806 described above is further configured to: read the data space corresponding to the first descriptor, wherein the data space is used to indicate the state of the first descriptor; determine the reference count included in the data space, wherein the reference count is used to indicate the number of threads currently accessing the target file; and close the target file based on the second descriptor if the reference count is a preset number.
[0190] Optionally, the mapping table adjustment module 806 is further configured to: set the data space corresponding to the first descriptor to a first locked state, wherein the first locked state is used to indicate that the data space is prohibited from being accessed by at least one second thread, and the second thread is not the first thread; set the close indicator bit included in the data space to a first preset value, wherein the first preset value is used to indicate that the first descriptor is in a closed state; and set the data space corresponding to the first descriptor to a first unlocked state, wherein the first unlocked state is used to indicate that the data space can be accessed by the first thread and at least one second thread.
[0191] Optionally, the lookup module 804 described above is further configured to: set the descriptor mapping table to a second locked state, wherein the second locked state is used to indicate that the descriptor mapping table is prohibited from being accessed by at least one second thread;
[0192] Optionally, the mapping table adjustment module 806 described above is further configured to: set the descriptor mapping table to a second unlocked state, wherein the second unlocked state is used to indicate that the descriptor mapping table can be accessed by a first thread and at least one second thread.
[0193] Optionally, the first receiving module 802 described above is further configured to: receive a second instruction sent by a third thread, wherein the second instruction is used to instruct the opening of a target file, wherein the third thread and the first thread belong to the same process space; generate a first descriptor and a second descriptor; establish a mapping relationship between the first descriptor and the second descriptor; access the descriptor mapping table and store the mapping relationship in the descriptor mapping table.
[0194] Optionally, the lookup module 804 described above is further configured to: set the descriptor mapping table to a third locked state, wherein the third locked state is used to indicate that the descriptor mapping table is prohibited from being accessed by at least one fourth thread, the fourth thread being a non-third thread; and set the descriptor mapping table to a third unlocked state, wherein the third unlocked state is used to indicate that the descriptor mapping table can be accessed by a third thread and at least one fourth thread.
[0195] Optionally, the first receiving module 802 described above is further configured to: receive a third instruction sent by the fifth thread, wherein the third instruction is used to instruct reading data in the target file or writing data to the target file, the third instruction includes a first descriptor, and the fifth thread and the first thread belong to the same process space; access the descriptor mapping table to find the second descriptor corresponding to the first descriptor; if the first descriptor exists in the descriptor mapping table, read the data space corresponding to the first descriptor and increment the reference count included in the data space by one; execute the read or write operation indicated by the third instruction on the target file; and decrement the reference count included in the data space by one.
[0196] Optionally, the first receiving module 802 described above is further configured to: set the data space corresponding to the first descriptor to a fourth locked state, wherein the fourth locked state is used to indicate that the data space is prohibited from being accessed by at least one sixth thread, and the sixth thread is not the fifth thread; increment the reference count included in the data space; set the data space corresponding to the first descriptor to a fourth unlocked state, wherein the fourth unlocked state is used to indicate that the data space can be accessed by the fifth thread and at least one sixth thread; set the data space corresponding to the first descriptor to a fourth locked state; decrement the reference count included in the data space; and set the data space corresponding to the first descriptor to a fourth unlocked state.
[0197] Optionally, the search module 804 is further configured to: return a first prompt message if the first descriptor does not exist in the descriptor mapping table, wherein the first prompt message is used to indicate that the first descriptor is unavailable; determine the value of the close indicator bit included in the data space; and return a second prompt message if the value of the close indicator bit is a first preset value, wherein the second prompt message is used to indicate that the first descriptor is unavailable.
[0198] For a description of the features in the embodiments corresponding to the multi-threaded file management device, please refer to the relevant descriptions in the embodiments corresponding to the multi-threaded file management method, which will not be repeated here.
[0199] Embodiments of this application also provide an electronic device, including a memory and a processor, wherein the memory stores a computer program, and the processor is configured to run the computer program to perform the steps in any of the above-described multithreaded file management method embodiments.
[0200] Embodiments of this application also provide a computer-readable storage medium storing a computer program, wherein the computer program is configured to execute the steps in any of the above-described multithreaded file management method embodiments when running.
[0201] In one exemplary embodiment, the aforementioned computer-readable storage medium may include, but is not limited to, various media capable of storing computer programs, such as a USB flash drive, read-only memory (ROM), random access memory (RAM), portable hard disk, magnetic disk, or optical disk.
[0202] Embodiments of this application also provide a computer program product, which includes a computer program that, when executed by a processor, implements the steps in any of the above-described multi-threaded file management method embodiments.
[0203] Embodiments of this application also provide another computer program product, including a non-volatile computer-readable storage medium storing a computer program, which, when executed by a processor, implements the steps in any of the above-described multi-threaded file management method embodiments.
[0204] Those skilled in the art will further recognize that the units and algorithm steps of the various examples described in conjunction with the embodiments disclosed herein can be implemented in electronic hardware, computer software, or a combination of both. To clearly illustrate the interchangeability of hardware and software, the components and steps of the various examples have been generally described in terms of functionality in the foregoing description. Whether these functions are implemented in hardware or software depends on the specific application and design constraints of the technical solution. Those skilled in the art can use different methods to implement the described functions for each specific application, but such implementation should not be considered beyond the scope of this application.
[0205] The foregoing has provided a detailed description of a multi-threaded file management method, apparatus, storage medium, and electronic device provided in this application. Specific examples have been used to illustrate the principles and implementation methods of this application. The descriptions of the embodiments above are only intended to aid in understanding the method and core ideas of this application. It should be noted that those skilled in the art can make various improvements and modifications to this application without departing from its principles, and these improvements and modifications also fall within the protection scope of the claims of this application.
Claims
1. A multi-threaded file management method, characterized in that, include: Receive a first instruction sent by a first thread, wherein the first instruction is used to instruct the target file to be closed, and the first instruction includes a first descriptor; Set the descriptor mapping table to a second locked state, wherein the second locked state is used to indicate that the descriptor mapping table is prohibited from being accessed by at least one second thread; Access the descriptor mapping table to find the second descriptor corresponding to the first descriptor, wherein the second descriptor is used to indicate the target file, and the descriptor mapping table is used to store the mapping relationship between the first descriptor and the second descriptor; If the first descriptor exists in the descriptor mapping table, the mapping relationship is deleted, and the descriptor mapping table is set to a second unlocked state, wherein the second unlocked state is used to indicate that the descriptor mapping table can be accessed by the first thread and at least one second thread; Read the data space corresponding to the first descriptor, wherein the data space is used to indicate the state of the first descriptor; Set the data space corresponding to the first descriptor to a first locked state, wherein the first locked state is used to indicate that the data space is prohibited from being accessed by at least one second thread, and the second thread is not the first thread; Set the off indicator bit included in the data space to a first preset value, wherein the first preset value is used to indicate that the first descriptor is in a closed state; Determine the number of references included in the data space, wherein the number of references is used to indicate the number of threads currently accessing the target file; If the number of references is a preset number, the target file is closed based on the second descriptor; Set the data space corresponding to the first descriptor to a first unlock state, wherein the first unlock state is used to indicate that the data space can be accessed by the first thread and at least one second thread; Prior to receiving the first instruction sent by the first thread, the process includes: Receive a second instruction sent by a third thread, wherein the second instruction is used to instruct the opening of the target file, wherein the third thread and the first thread belong to the same process space; Generate the first descriptor and the second descriptor; Establish the mapping relationship between the first descriptor and the second descriptor; Set the descriptor mapping table to a third locked state, wherein the third locked state is used to indicate that the descriptor mapping table is prohibited from being accessed by at least one fourth thread, and the fourth thread is not the third thread; Access the descriptor mapping table and store the mapping relationship in the descriptor mapping table; Set the descriptor mapping table to a third unlock state, wherein the third unlock state is used to indicate that the descriptor mapping table can be accessed by the third thread and at least one fourth thread.
2. The method according to claim 1, characterized in that, After storing the mapping relationship in the descriptor mapping table, the following steps are included: Receive a third instruction sent by a fifth thread, wherein the third instruction is used to instruct reading data from the target file or writing data to the target file, the third instruction includes the first descriptor, and the fifth thread and the first thread belong to the same process space; Access the descriptor mapping table to find the second descriptor corresponding to the first descriptor; If the first descriptor exists in the descriptor mapping table, read the data space corresponding to the first descriptor and increment the reference count included in the data space by one; Perform the read or write operation indicated by the third instruction on the target file; Decrease the number of references included in the data space by one.
3. The method according to claim 2, characterized in that, Increasing the reference count of the data space by one includes: Set the data space corresponding to the first descriptor to a fourth locking state, wherein the fourth locking state is used to indicate that the data space is prohibited from being accessed by at least one sixth thread, and the sixth thread is not the fifth thread; Increment the number of references included in the data space by one; Set the data space corresponding to the first descriptor to a fourth unlock state, wherein the fourth unlock state is used to indicate that the data space can be accessed by the fifth thread and at least one of the sixth threads; The step of decrementing the reference count of the data space by one includes: Set the data space corresponding to the first descriptor to the fourth locking state; Decrease the number of references included in the data space by one; Set the data space corresponding to the first descriptor to the fourth unlock state.
4. The method according to claim 3, characterized in that, After accessing the descriptor mapping table and looking up the second descriptor corresponding to the first descriptor, the process includes: If the first descriptor does not exist in the descriptor mapping table, a first prompt message is returned, wherein the first prompt message is used to indicate that the first descriptor is unavailable; Setting the data space corresponding to the first descriptor to the fourth locked state includes: Determine the value of the close indicator bit included in the data space; If the value of the closed indicator bit is a first preset value, a second prompt message is returned, wherein the second prompt message is used to indicate that the first descriptor is unavailable.
5. An electronic device, characterized in that, include: Memory, used to store computer programs; A processor, configured to implement the steps of the multithreaded file management method as described in any one of claims 1 to 4 when executing the computer program.
Citation Information
Patent Citations
Process context mandatory access control method
CN104133726A
Data real-time storage system and method based on Linux
CN111338853A