使用单例模式并跨线程传递数据实践
背景
程序接入一个手柄作为输入设备,手柄摇杆的位置值可能被其他任务(可能不止一个)所使用。
解决方案
由于只有其他任务只会使用手柄数据,而不会写入,对其他任务来说,手柄数据是只读的。可以使用一个任务读取手柄数据,而其他任务通过接口读取即可。手柄对象设计采用单例模式,数据采集任务中通过一个手柄对象去读取外设的数据,而其他任务中只调用读取手柄数据的接口。
具体实现
手柄类声明部分
static std::mutex joystic_mtx;
class Joystick{
public:
static Joystick* Getinstance() {
if (instance_ == NULL) {
std::lock_guard<std::mutex> guard(joystic_mtx);
if (instance_ == NULL) {
instance_ = new Joystick();
static GarCollector gc;
}
}
return instance_;
}
void operator()();
bool isJoystickValid();
void GetJoyXYPos(int& wXpos, int& wYpos);
void ReadJoystick();
private:
Joystick(){};
void TranslateJoyPos();
class GarCollector {
public:
~GarCollector() {
if (Joystick::instance_) {
delete Joystick::instance_;
Joystick::instance_ = NULL;
}
}
};
static Joystick* instance_;
JOYINFO joy_basic_info_; // 定义joystick信息结构体
MMRESULT valid_flag_;
int xy[2] = {0, 0};
};
其中 Getinstance
函数中采用了[[使用单例模式进行多线程编程]]中所提到的双重判定写法,确保在多个线程实例化切线程的过程中不会误判断。另外,使用 GarCollector
来保障资源回收。
手柄类实现部分
Joystick *Joystick::instance_ = NULL;
bool Joystick::isJoystickValid() {
if (valid_flag_ == JOYERR_NOERROR) return TRUE;
return FALSE;
}
void Joystick::GetJoyXYPos(int &Xpos, int &Ypos) {
Xpos = xy[0];
Ypos = xy[1];
}
void Joystick::operator()() {
ReadJoystick();
TranslateJoyPos();
}
void Joystick::TranslateJoyPos() {
const int sample_limit = 65536 / 2;
const int valid_threshold = sample_limit / 10;
xy[0] = std::abs(sample_limit - int(joy_basic_info_.wXpos)) < valid_threshold
? 0
: int(joy_basic_info_.wXpos) - sample_limit;
xy[1] = std::abs(sample_limit - int(joy_basic_info_.wYpos)) < valid_threshold
? 0
: sample_limit - int(joy_basic_info_.wYpos);
}
void Joystick::ReadJoystick() {
valid_flag_ = joyGetPos(JOYSTICKID1, &joy_basic_info_);
}
多线程并行读取数据方式
void joystick_thread() {
Joystick* joystick = Joystick::Getinstance();
joystick->ReadJoystick();
while (true) {
if (joystick->isJoystickValid()) {
(*joystick)();
Sleep(100);
} else {
cout << "please make sure joystick is valid" << endl;
Sleep(1000);
joystick->ReadJoystick();
}
}
}
void get_joystick_thread() {
Joystick* joystick = Joystick::Getinstance();
int xpos, ypos;
while (true) {
joystick->GetJoyXYPos(xpos, ypos);
if (joystick->isJoystickValid()) {
cout << Format("x is {0}, y is {1}", xpos, ypos) << endl;
}
Sleep(500);
}
}
int main() {
Joystick* joystick = Joystick::Getinstance();
std::thread joystick_th(joystick_thread);
std::thread get_joystick_th(get_joystick_thread);
joystick_th.join();
get_joystick_th.join();
return EXIT_SUCCESS;
}
joystick_thread
线程一直读取手柄的输入数据,并存到 joystick
类中,get_joystick_thread
作为其他任务读取 joystick
类中的数据并使用。
Reference
时间仓促,如有错误欢迎指出,欢迎在评论区讨论,如对您有帮助还请点个推荐、关注支持一下
作者: pomolnc
出处: https://www.cnblogs.com/pomolnc/p/17782874.html
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文链接,否则保留追究法律责任的权利。
若内容有侵犯您权益的地方,请公告栏处联系本人,本人定积极配合处理解决。