linux mutex lock: pthread_mutex_t mutex_lock

#include <stdio.h>
#include <pthread.h>  

pthread_mutex_t mutex_lock;  
static volatile int count = 0;  

void *test_func(void *arg)  
{  
    int i = 0;  
    for(i = 0; i < 2000000; i++)  
    {  
            pthread_mutex_lock(&mutex_lock); // a thread should get this mutex lock first.
            count++; // at one time, this grobal var can be accessed by only one thread which holds this mutex lock.
            pthread_mutex_unlock(&mutex_lock); // after access, thread should release this lock.
    }  
    return NULL;  
}  

int main(void)
{
	pthread_mutex_init(&mutex_lock, NULL);
	pthread_t thread_ids[10];  
	int i = 0;  
	for(i = 0; i < sizeof(thread_ids)/sizeof(pthread_t); i++)  
	{  
	    pthread_create(&thread_ids[i], NULL, test_func, NULL);  
	}  
	
	for(i = 0; i < sizeof(thread_ids)/sizeof(pthread_t); i++)  
	{  
	    pthread_join(thread_ids[i], NULL);	// wait threads to exit.
	}
	
	printf("count: %d\n", count);
	return 0;
}

the execution result:
count: 20000000	// 2000000 * 10(10 threads)


 

<think>我们正在解决一个特定的Android Native崩溃问题:`FORTIFY: pthread_mutex_lock called on a destroyed mutex` 引用内容中显示了一个函数`HandleUsingDestroyedMutex`,它在检测到对已销毁的互斥锁调用`pthread_mutex_lock`时会触发`__fortify_fatal`(当targetSdkVersion>=28时)。 错误信息明确:我们试图对一个已经被销毁(destroyed)的互斥锁(mutex)进行加锁操作。 解决步骤: 1. **理解错误原因**: - 当一个互斥锁被`pthread_mutex_destroy`销毁后,再次对其执行`pthread_mutex_lock`(或解锁等操作)是未定义行为(UB)。 - Android在targetSdkVersion>=28(Android 9.0)时,通过FORTIFY功能加强了检查,会主动中止程序(abort)并打印该错误信息。 - 这通常是由于代码中出现了“使用已销毁的互斥锁”的bug。 2. **常见错误场景**: a. **双重销毁**:多次销毁同一个互斥锁,第一次销毁后互斥锁变为无效,第二次销毁可能导致后续使用已经销毁的互斥锁。 b. **生命周期不一致**: - 互斥锁被销毁后,某个线程仍然持有该互斥锁的指针并尝试使用它。 - 常见于全局/静态互斥锁在程序退出时被销毁,但其他线程还在运行并尝试使用它。 - 或者局部互斥锁在超出作用域后(被自动销毁)但仍有线程尝试访问。 c. **未初始化或未销毁的互斥锁**:未初始化就使用,或者未销毁就重新初始化,也可能导致类似问题。 3. **调试方法**: a. **检查堆栈跟踪**:崩溃时的堆栈跟踪(stack trace)是首要线索。找到调用`pthread_mutex_lock`的位置,以及互斥锁在何处被销毁。 b. **排查互斥锁的生命周期**: - 确保互斥锁在使用前被正确初始化(`pthread_mutex_init`或`PTHREAD_MUTEX_INITIALIZER`)。 - 确保互斥锁在不再需要时销毁(`pthread_mutex_destroy`),且销毁后不再使用。 - 特别注意全局互斥锁:在程序退出时,应确保所有线程都已结束,再销毁互斥锁。 c. **使用内存调试工具**: - AddressSanitizer (ASan):可以检测内存错误,包括使用已释放的内存(这里互斥锁被销毁后,其内存可能被重用)。 - Valgrind:虽然Android上使用较麻烦,但也可以尝试。 - Android NDK原生工具:如`ndk-stack`解析崩溃日志。 4. **代码审查要点**: - 查找所有对互斥锁进行销毁(`pthread_mutex_destroy`)的代码,并检查在销毁后是否有可能被使用的路径。 - 检查多线程同步逻辑:确保没有线程会在互斥锁销毁后尝试获取它。 - 检查对象的析构函数:如果互斥锁是某个类的成员,确保在析构函数中销毁互斥锁时,没有其他线程会调用该对象的成员函数(因为成员函数可能会使用互斥锁)。 5. **解决方案**: - **确保销毁顺序**:在程序退出或对象销毁时,必须先确保没有线程会再使用该互斥锁,然后再销毁它。 - 例如,使用条件变量通知所有线程退出,等待所有线程结束,然后销毁互斥锁和条件变量。 - **避免全局互斥锁**:尽量使用对象内部的互斥锁,并严格管理对象生命周期。 - **延迟销毁**:如果不确定是否有线程还在使用互斥锁,可以延迟销毁(例如在程序退出时不销毁,由系统自动回收。但这可能掩盖问题,不推荐)。 - **使用智能管理**:在C++中,可以使用RAII技术管理互斥锁生命周期: ```cpp class MutexLock { public: MutexLock() { pthread_mutex_init(&mutex_, nullptr); } ~MutexLock() { pthread_mutex_destroy(&mutex_); } void lock() { pthread_mutex_lock(&mutex_); } void unlock() { pthread_mutex_unlock(&mutex_); } private: pthread_mutex_t mutex_; }; ``` 这样,只要对象的生命周期管理得当,互斥锁的初始化和销毁就会自动进行。 6. **特殊情况**: - 如果互斥锁是静态全局变量,注意C++11保证了静态局部变量的线程安全初始化,但销毁顺序仍然可能有问题(在程序退出时)。 - 可以考虑使用`std::mutex`(在C++11及以上)代替,因为它的行为更可预测(但注意Android NDK完全支持C++11)。 - 或者使用`pthread_mutex_t`配合`PTHREAD_MUTEX_INITIALIZER`进行静态初始化,且永不显式销毁(在程序整个生命周期使用,退出时不销毁)。因为程序结束时系统会回收资源,但需确保销毁前没有线程会再使用。 7. **示例修复**: 假设有以下问题代码: ```c static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void thread_work() { pthread_mutex_lock(&mutex); // ... do work pthread_mutex_unlock(&mutex); } void cleanup() { pthread_mutex_destroy(&mutex); // 销毁互斥锁 } ``` 如果在调用`cleanup()`后还有线程调用`thread_work()`,就会出现此错误。 修复:确保所有线程结束后再销毁互斥锁: ```c void cleanup() { // 等待所有工作线程结束 join_all_worker_threads(); pthread_mutex_destroy(&mutex); } ``` 8. **注意事项**: - 在targetSdkVersion>=28时,此错误会导致程序立即中止(abort),因此必须修复。 - 低于28的targetSdkVersion不会触发abort,而是返回EBUSY(根据引用中的函数逻辑),但这只是侥幸,代码仍有bug。 9. **工具辅助**: - 使用日志跟踪互斥锁的生命周期:在初始化、加锁、解锁、销毁时打印日志。 - 使用`pthread_mutex_t`的地址作为标识,在日志中输出。 10. **总结步骤**: 1. 通过崩溃堆栈定位问题互斥锁和调用位置。 2. 检查该互斥锁的初始化和销毁位置。 3. 确保销毁互斥锁时,没有任何线程会再尝试使用它(包括加锁、解锁等操作)。 4. 使用工具(如ASan)辅助检测内存违规。 5. 修复生命周期管理,或使用RAII封装。 生成相关问题: 1. 如何避免多线程环境下互斥锁的双重销毁问题? 2. Android NDK中如何正确使用AddressSanitizer检测内存错误? 3. 在C++中如何使用RAII技术管理pthread_mutex_t? 4. 为什么Android在targetSdkVersion>=28时加强了FORTIFY检查? 5. 如何调试Android Native层的并发问题? 注意:引用内容中给出了触发崩溃的代码,我们可以参考: 当targetSdkVersion>=28时,会调用`__fortify_fatal`导致崩溃,因此定位到问题后,也要检查targetSdkVersion的设置。 </think>### 解决 `FORTIFY: pthread_mutex_lock called on a destroyed mutex` 错误的方法 #### 1. **错误原因分析** 该错误表明代码尝试对**已销毁的互斥锁(mutex)** 进行加锁操作,常见原因包括: - ✅ 互斥锁被重复销毁(双重销毁) - ✅ 线程尝试访问已被销毁的互斥锁(生命周期管理错误) - ✅ 互斥锁未初始化或初始化失败 - ✅ 跨线程访问时同步机制失效 引用中的代码显示这是Android的FORTIFY安全检查机制(targetSdkVersion ≥ 28时生效)[^1] --- #### 2. **排查与修复步骤** ##### (1) 检查互斥锁生命周期 ```c++ pthread_mutex_t mutex; void init() { pthread_mutex_init(&mutex, nullptr); // ✅ 正确初始化 } void destroy() { pthread_mutex_destroy(&mutex); // ❌ 确保后续无访问 } void thread_func() { pthread_mutex_lock(&mutex); // 崩溃点:若在destroy()后调用 } ``` **修复方案**: - 使用RAII模式封装互斥锁 - 确保销毁前所有线程已退出 ##### (2) 避免双重销毁 ```c++ class MutexGuard { public: MutexGuard() { pthread_mutex_init(&mutex_, nullptr); } ~MutexGuard() { if(!destroyed_) { pthread_mutex_destroy(&mutex_); destroyed_ = true; // ✅ 标记销毁状态 } } private: pthread_mutex_t mutex_; bool destroyed_ = false; }; ``` ##### (3) 验证初始化状态 在加锁前添加状态检查: ```c++ void safe_lock(pthread_mutex_t* mutex) { static std::atomic<bool> initialized{false}; if (!initialized.load()) { pthread_mutex_init(mutex, nullptr); initialized.store(true); } pthread_mutex_lock(mutex); } ``` ##### (4) 使用Android特有调试工具 通过`adb logcat`捕获完整堆栈: ```bash adb logcat -s "FORTIFY" # 过滤FORTIFY错误 adb logcat | ndk-stack -sym ./obj/local/armeabi-v7a # 符号化堆栈 ``` --- #### 3. **预防措施** | 措施 | 说明 | |--------------------------|-------------------------------| | **RAII封装** | 使用`std::mutex`(C++11)替代原始操作 | | **作用域控制** | 互斥锁生命周期不超过持有它的对象 | | **静态分析工具** | 使用Clang的`-Wthread-safety`选项 | | **线程清理顺序** | 退出时先停止线程再销毁互斥锁[^1] | --- #### 4. **示例修复代码** ```c++ #include <pthread.h> #include <memory> class SafeMutex { public: SafeMutex() { pthread_mutex_init(&mutex_, nullptr); } ~SafeMutex() { pthread_mutex_destroy(&mutex_); } void lock() { pthread_mutex_lock(&mutex_); } void unlock() { pthread_mutex_unlock(&mutex_); } private: pthread_mutex_t mutex_; }; // 使用示例 void worker_thread(std::shared_ptr<SafeMutex> mtx) { mtx->lock(); // 临界区操作 mtx->unlock(); } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值