×

Loading...
Ad by
  • 予人玫瑰,手有余香:加拿大新天地工作移民诚聘求职顾问&行业导师!
Ad by
  • 予人玫瑰,手有余香:加拿大新天地工作移民诚聘求职顾问&行业导师!

你其实已经知道怎么做了。这里是我的想法。

Image and video hosting by TinyPic

我的UML的工具还是Java的,有些type象boolean之类的就没改,请将就着看吧。

每一路资源,似乎是一个相当独立的对象。占用和释放资源,可以在资源上标记(isAllocated)。锁是在USB Device上,多个device的时候,每个有自己的锁。

用interface(纯虚类)的好处是decoupling,而且,你可以定义一个MockDevice对你的应用进行各种测试,否则,你不得不从硬件上模拟各种情况。

对于多线程,加锁是一种简单的办法,缺点是,如果操作时间长,其它的线程就被锁住了。另一种办法是给device分配一个worker线程和一个operation queue,让Controller把operation放到queue里,fire and forget。适用于可以异步的操作。

指针并不可怕,在C++可以用引用。
Report

Replies, comments and Discussions:

  • 工作学习 / 科技领域杂谈 / C++ OO 程序设计简单问题请教。
    本文发表在 rolia.net 枫下论坛问题应该非常简单,可是我没想明白。

    有一个USB接口的I/O设备,可以读取4路encoder信号,还有A/D输出,以及一些数字IO。我在这个设备上面实现了非常简单的4路电机控制器,其中每一路用到USB设备的一路encoder,A/D等。设备SDK提供底层函数,通过对寄存器的读写来操作I/O设备。

    我开始想的很简单,定义了Controller类。在Controller类的设置速度、启动,停止等成员函数里面通过直接操作USB设备寄存器实现了相应功能。有一些controller共享的寄存器,我偷懒,就定义成全局变量,把指针传递给controller对象。这个味道就已经不太好了。

    后来出现了问题,SDK的低层函数不是线程安全的。而我的程序是多线程的,需要加个锁。于是我增加了一个关键区锁(windows环境)。由于4个控制器都是基于同一个USB设备的,需要共享这个锁,于是我就想到了在controller 类里面把锁定义为静态变量,由所有controller对象共享。到这里我想到了静态成员函数的必要性问题,于是发了上个贴子。

    下面是本贴真正的问题了:我发现应该有一个USB设备的类,在这个类上定义硬件资源,因为I/O等硬件资源本来就是属于USB设备的,只是分配给了不同的controller。更重要的是我的应用中需要不止一个USB设备。

    问题是USB类和controller的关系是怎样的?我想到USB设备上实现了4个控制器,于是就在USB类里面定义了4个controller 对象。这个好像有点问题。现在,寄存器、锁等资源都改在USB类里面定义了。

    (1) 这时候是不是应该把对低层函数的调用都放到USB类里面?这样好像更符合逻辑。如果这样,controller对象应该怎样调用这些函数哪?因为最终controller的功能要通过这些函数操作寄存器来实现。

    我还没有这样做,我只是把关键区锁定义在USB类中,并且把锁的指针传递给controller对象,让他们共享这个锁。这样做应该是不对的,因为这样controller 和USB对象都要访问低层函数,显然不合理。

    (2) Controller 类应该知道USB设备对象,因为它要知道它的功能是基于哪一个USB硬件实现的,这样,我是不是在构造controller对象的时候,要把USB对象的指针或引用作为参数传递给controller?这样做合理吗?我总觉得这个地方有点不对,有什么更好的办法?

    这些问题对高手应该非常简单,请提供意见,谢谢。更多精彩文章及讨论,请光临枫下论坛 rolia.net
    • 你的问题看得一头雾水(因为我不是什么高手),能不能发点伪代码上来,让大家看看你的类怎么定义的,主要的方法以及如何调用。这样可能能解释得比较清楚。
      • 呵呵,应该是我写得不清楚,把简单的问题说复杂了。其实我的问题主要两点:(1)对低层函数的访问是不是应该放到USB类里面?从controller类里面怎么访问这些函数?(2)用什么办法让controller对象“知道”USB对象最合适?等我看看能不能把代码发上来。
    • 1)低层函数的调用和线程同步(锁)都放到USB类2)USB向controller提供封装好的简化的线程安全的服务(public member functions)3)USB和controller是一对多的关系。在controller类中设一指针指向它所使用的USB对象
      • 这个跟我想的差不多。3)里面除了给controller对象传递USB对象的指针,有没有其他的好办法? 还有,我把4个controller 对象放到USB类里面作成员变量。有没有更合理的安排?谢谢。
        • 1) "除了给controller对象传递USB对象的指针,有没有其他的好办法?" - 这种设计太常用了,有什么问题吗?2) "把4个controller 对象放到USB类里面作成员变量" - USB需要知道controller吗?
          • (1)没什么问题,就是我最近对指针有点害怕。(2)也是我正在纠结的问题,USB类似无必要知道controller。不过每个controller对象都要独占USB对象的某些资源,似乎让controller对象到USB对象里面去“注册”取得这些资源更合理。否则,错误的重复占用怎么处理?
            可能是我想多了。

            如果USB不知道controller,那么每个controller就应该记住自己使用哪些资源。在调用被包装过底层函数的时候,把这些资源的ID作为参数传递给USB类,这样好像比较合理。
            • USB类应该不用知道Controller,只需要分配资源。最简单的设计是资源分配和释放都在一次调用中完成,下次调用重新分配。多个controller如果同时调用,就只有一个可以进入,其它的等待或者失败,等待一段时间后重试。这样的程序可靠性最高。如果这样不行
              你的思路也可以。一般可以有一对分配/释放资源的方法,分配时返回一个token给controller, controller记住这个token, 每次用这个token就可以使用资源,用完后释放资源,token失效。这个token就是Controller记住的自己占用的资源。这种设计关键要记得释放资源,尤其是在出错的时候,否则别的Controller就永远无法获得资源了。
              • 我的controller独占的资源是不变的,比如某个控制器占用了那些I/O端口,分配一次就可以了。共享的资源是在USB里面定义的,然后把指针传递给controller。
            • 要在战略上藐视指针,在战术上重视指针。不过看样子你对C++和OO都只是一知半解。。。
              • 是啊,我C++还没入门,OO更别提了。还有个问题顺便请教,C#和Java好像是没有指针的,那么一个这种情况(一个对象需要使用另一个对象定义的资源)怎么解决呐?
                • 如果你必须要在你的APP里做这些事情,建议如下:
                  建议所有硬件的功能,资源共享和锁的操作全封装进USB_DEVICE_CLASS()。但是,同时建议创建USB_DEVICE_USER_CLASS()提供接口给所有用户用,把所有controller需要用到的USB device API全封装进这个类里。

                  从全局看,你的一个controller就是一个USB 的设备用户,所以如果另外给controller创建对象的话,每个Controller class除了实现各自的逻辑,还必须得到一个USB_DEVICE_USER_CLASS()的instance用来具体操作这个对应的USB device。

                  这样,USB_DEVICE_CLASS() 知道USB_DEVICE_USER_CLASS(),但不用知道具体的Controller class。但是,USB_DEVICE_USER_CLASS()的instance的alloc/dealloc的操作一般需要由USB_DEVICE_CLASS()来实现。
                  • 好像我现在做的就和你说的差不多,我的controller类其实就是你说的user class。我在USb class 里面定义了4个controller instance.
                    • 如果你的controller class不是为了把USB接口抽象化,还有其他逻辑在里面的话,这区别就很大,很不同。由USB_DEVICE_CLASS()可以看做一个CONTAINER,由它分配得到的USB_DEVICE_USER_CLASS()的INSTANCE只包含USB device有关的逻辑,对应一个设备。
                      而具体用户是谁,用户有什么其他的逻辑和处理对USB_DEVICE_CLASS()来说是根本不需要考虑的。

                      从模块化设计的考虑,用户的controller class应该和USB_DEVICE_USER_CLASS()分开。甚至USB模块提供的接口USB_DEVICE_USER_CLASS()可以完全是一个virtual class。具体实现完全包含在USB模块内部。

                      当然,如果你的controller class和我说的一致的话,就应该没什么问题了。为了系统设计更清晰,可以将接口虚拟化。
                      • 这回才看明白,等我再想想。
    • 你这个不是static不static的问题。在windows platform上,最规范的做法不是自己去处理设备共享问题,应该给你的device写一个驱动程序,windows已经给你搭好框架处理这些硬件资源的共享问题了。根据你的application需求,决定选择user mode driver还是kernal mode driver。
      我对windows driver development只是了解皮毛,不过估计你选择用miniport driver的model就可以了。
      • 谢谢。static只是我编程时有了一些想法,不是本贴 的主题。还要写驱动程序?这个有点太夸张了吧?这个驱动程序好像应该已经有了,我所说的底层函数应该还在驱动的上面,相当于驱动给应用程序的接口,也不知道我理解得对不对。
        • 驱动程序是最规范标准的做法。而且WDF已经提供了框架处理资源共享的问题,写驱动程序的时候程序员不用自己创建和处理什么锁之类的,应该说是规范了程序员的工作。
          另外,Windows/Linux等平台上,在用户空间直接对硬件进行操作是不规范的做法。
          • 看来我需要学的东西太多了。
    • 你其实已经知道怎么做了。这里是我的想法。
      Image and video hosting by TinyPic

      我的UML的工具还是Java的,有些type象boolean之类的就没改,请将就着看吧。

      每一路资源,似乎是一个相当独立的对象。占用和释放资源,可以在资源上标记(isAllocated)。锁是在USB Device上,多个device的时候,每个有自己的锁。

      用interface(纯虚类)的好处是decoupling,而且,你可以定义一个MockDevice对你的应用进行各种测试,否则,你不得不从硬件上模拟各种情况。

      对于多线程,加锁是一种简单的办法,缺点是,如果操作时间长,其它的线程就被锁住了。另一种办法是给device分配一个worker线程和一个operation queue,让Controller把operation放到queue里,fire and forget。适用于可以异步的操作。

      指针并不可怕,在C++可以用引用。
      • 非常感谢你详细的解说,让我先想一下。