高通SSE架构HAL要与底层ADSP Sensor通信,必须获取对应的SUID, 通过构造suid_lookup以及request_suid来建立连接,request成功后会调用callback,callback与主线程是异步的,若主线程结束的早时,构造的资源被回收就会导致callback异常。下面的demo强行造了一个多线程问题,当智能指针unique_ptr会被系统回收,出现值不对,当然真实的比这个复杂的多。
异常代码
#include <thread>
#include <iostream>
#include <stdio.h>
#include <memory>
#include <unistd.h>
/*
g++ thread.cpp -std=c++14 -lpthread
use -lpthread
undefined reference to `pthread_create'
use g++
thread.cpp:(.text+0xdb): undefined reference to `std::cout'
use -std=c++11
#error This file requires compiler and library support for the ISO C++ 2011 standard.
use -std=c++14
#error: ‘make_unique’ was not declared in this scope
*/
using namespace std;
void func1(const int i, int* p){
sleep(1);
cout << "child thread 引用地址" << &i << endl;
cout << "child thread 指针地址" << p << endl;
cout << "child thread val = " << *p << endl;
//add here 1
}
void test1(){
unique_ptr<int> p;
p = make_unique<int>();
int var = 1;
*p = 2;
cout << "main thread 引用地址" << &var << endl;
cout << "main thread 指针地址" << p.get() <<endl;
cout << "main thread val = " << *p << endl;
thread thread1(func1, var, p.get());
thread1.detach();
//add here 2
}
int main(){
test1();
sleep(1);
cout << "main thread exit" << endl;
return 0;
}
分析异常
main thread 引用地址0x7ffdc320fafc
main thread 指针地址0xb45c20
main thread val = 2
child thread 引用地址0x7f3159f0ee4c
child thread 指针地址0xb45c20
child thread val = 0
main thread exit
可以看到传入的变量地址发生变化,中间必然产生拷贝的过程,而传入的指针地址没有发生变化,当子函数test1结束后就会导致unique_ptr p会系统回收,所以就会出现两次打印的值不对的情况
互斥锁机制
std::condition_variable与std::unique_lock的结合使用
互斥量std::mutex、锁对象lock_guard和unique_lock 及 条件变量std::condition_variable
当线程调用信号量的wait的时候,会把锁给打开,这样其他的线程就能执行,当wait函数遇到唤醒函数notify时,线程会由阻塞转为运行状态,此时锁会直接锁上,即使其他线程也被唤醒,也会阻塞,直到第一个被唤醒的线程执行完毕,跳出unique_lock的执行范围。
std::unique_lockstd::mutex lock只有在没上锁的情况下才能被构造,已上锁的不能被构造,一直处于等地状态,等待锁被释放后再构造。
//add here 1
std::unique_lock<std::mutex> lck(mtx);
ready = true;
cv.notify_all();
//add here 2
std::unique_lock<std::mutex> lck(mtx);
while (!ready) cv.wait(lck); //阻塞进程
高通源码中也由很多使用mutex和condition variable结合的例子
vendor/qcom/proprietary/sensors-see/test/ssc_sensor_info/ssc_sensor_info.cpp
vendor/qcom/proprietary/sensors-see/test/sns_client_test_cpp_cmdline_args/src/ssc_connection_reference.cpp