【问题标题】:In Java how to cast an interface properly?在Java中如何正确转换接口?
【发布时间】:2014-12-14 16:26:52
【问题描述】:

我正在学习使用 Rootbeer,但在运行它的示例应用程序时卡住了,没有人能回答我的问题:Rootbeer runtime error, how to fix?

于是我下载了Rootbeer的源代码,看了一下代码,问题出在[CUDAContext.java:119]:

          public void setKernel(Kernel kernelTemplate) {
            this.kernelTemplate = kernelTemplate;
 [ 119 ]    this.compiledKernel = (CompiledKernel) kernelTemplate;
          }

Kernel 和 CompiledKernel 的定义是:

public interface Kernel
{
  public void gpuMethod();
}

public interface CompiledKernel
{
  public String getCodeUnix();

  public String getCodeWindows();

  public int getNullPointerNumber();

  public int getOutOfMemoryNumber();

  public String getCubin32();

  public int getCubin32Size();

  public boolean getCubin32Error();

  public String getCubin64();

  public int getCubin64Size();

  public boolean getCubin64Error();

  public Serializer getSerializer(Memory memory,Memory memory1);

  public boolean isUsingGarbageCollector();
}

第 119 行的转换是否正确?如果是,为什么我会收到错误消息:

java.lang.ClassCastException: ArrayMult cannot be cast to org.trifort.rootbeer.runtime.CompiledKernel
    at org.trifort.rootbeer.runtime.CUDAContext.setKernel(CUDAContext.java:119)

如果没有正确完成,正确的投射方式是什么?

编辑:这里是示例代码

import java.util.List;
import java.util.ArrayList;
import org.trifort.rootbeer.runtime.Kernel;
import org.trifort.rootbeer.runtime.Rootbeer;

public class ArrayMultApp
{  
  public ArrayMultApp()
  {
    int[] array=new int[10];
    for (int i=0;i<array.length;++i) array[i]=i;
    for (int i=0;i<array.length;++i) Out("start array["+i+"]: "+array[i]);
    multArray(array);
    for (int i=0;i<array.length;++i) Out("final array["+i+"]: "+array[i]);
  }

  public void multArray(int[] array)
  {
    try
    {
      List<Kernel> jobs=new ArrayList();
      for (int i=0;i<array.length;++i) jobs.add(new ArrayMult(array,i));
      Rootbeer rootbeer=new Rootbeer();
      rootbeer.run(jobs);
    }
    catch (Exception e) { e.printStackTrace(); }
  }

  public static void main(String[] args) { ArrayMultApp app=new ArrayMultApp(); }

  private static void out(String message) { System.out.print(message); }

  private static void Out(String message) { System.out.println(message); }
}

class ArrayMult implements Kernel
{
  private int[] m_source;
  private int m_index;

  public ArrayMult(int[] source,int index)
  {
    m_source=source;
    m_index=index;
  }

  public void gpuMethod() { m_source[m_index]*=11; }
}

【问题讨论】:

  • 传递的Kernel 对象也没有实现CompiledKernel。你的意思是让CompiledKernel 扩展Kernel
  • 您不能将对象强制转换为它不是的类型,没有正确的方法可以做到这一点。这有点像在问,把橙子变成苹果的正确方法是什么,你不能,因为它不是苹果。
  • 我认为你没有以正确的方式初始化上下文。

标签: java interface casting rootbeer


【解决方案1】:

不,不是。你有两个不同的界面。

     public void setKernel(Kernel kernelTemplate) {
        this.kernelTemplate = kernelTemplate;
 [ 119 ]    this.compiledKernel = (CompiledKernel) kernelTemplate;
      }

在 119 上,您尝试将 Kernel 转换为 CompiledKernel,它们每个都有自己的层次结构。如果CompiledKernel extends Kernel,那么这将起作用。

【讨论】:

  • 不,只有在 Kernel 扩展 CompiledKernel 时才有效。
  • "Kernel extends CompiledKernel" 不会编译。现在我将其更改为“CompiledKernel extends Kernel” copmiles OK,但仍然得到相同的运行时错误。
【解决方案2】:

我没有 G 卡,因此无法测试您的代码。我查看了源代码。作者在 org.trifort.rootbeer.compiler.Transform2.java 中做了这个技巧

public void run(String cls){    
  OpenCLScene scene = new OpenCLScene();
  OpenCLScene.setInstance(scene);
  scene.init();

  SootClass soot_class1 = Scene.v().getSootClass(cls);
  SootMethod method = soot_class1.getMethod("void gpuMethod()");

  String uuid = getUuid();
  GenerateForKernel generator = new GenerateForKernel(method, uuid);
  try {
    generator.makeClass();
  } catch(Exception ex){
    ex.printStackTrace();
    OpenCLScene.releaseV();
    return;
  }

  //add an interface to the class
  SootClass soot_class = method.getDeclaringClass();
  SootClass iface_class = Scene.v().getSootClass("org.trifort.rootbeer.runtime.CompiledKernel");
  soot_class.addInterface(iface_class);

  System.out.println("added interface CompiledKernel");

  OpenCLScene.releaseV();
}

我还查看了他的演示代码“examples\sort\src\org\trifort\rootbeer\sort\GPUSort.java”。作者确实初始化了 Contex,这与您的代码不同。我建议你先试试他的代码。我敢打赌它会调用 Transform2.run 函数,而您的代码不会。

public void sort(){
  //should have 192 threads per SM
  int size = 2048;
  int sizeBy2 = size / 2;
  //int numMultiProcessors = 14;
  //int blocksPerMultiProcessor = 512;
  int numMultiProcessors = 2;
  int blocksPerMultiProcessor = 256;
  int outerCount = numMultiProcessors*blocksPerMultiProcessor;
  int[][] array = new int[outerCount][];
  for(int i = 0; i < outerCount; ++i){
    array[i] = newArray(size);
  }

  Rootbeer rootbeer = new Rootbeer();
  List<GpuDevice> devices = rootbeer.getDevices();
  GpuDevice device0 = devices.get(0);
  Context context0 = device0.createContext(4212880);
  context0.setCacheConfig(CacheConfig.PREFER_SHARED);
  context0.setThreadConfig(sizeBy2, outerCount, outerCount * sizeBy2);
  context0.setKernel(new GPUSortKernel(array));
  context0.buildState();
  ......
}

【讨论】:

  • 感谢您的洞察力,看来您正在做某事,但我不太明白,我运行的代码来自他的示例,我在网上发现其他人也有同样的问题代码,您建议我如何更改他的示例以使其正常工作?我刚刚将代码添加到问题中。
  • 尝试先编译这个例子github.com/pcpratts/rootbeer1/tree/master/examples/sort。注意 GPUSort.java 中第 60-67 行的代码。
  • 我试过了,在第 65 行 [setKernal] 得到“GPUSortKernel cannot be cast to org.trifort.rootbeer.runtime.CompiledKernel”
【解决方案3】:

如果实际对象实现了该接口,则只能转换为该接口。我对 CUDA 了解不多,但可能有一个方法需要一个内核,并返回一个 CompiledKernel。简单的强制转换是不行的。

另一方面,如果您是“ArrayMult”类的创建者,那么您可以通过同时实现 Kernel 和 CompiledKernel 来解决此问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-15
    • 2017-03-02
    • 2014-05-03
    • 1970-01-01
    • 2013-04-17
    • 2017-05-22
    相关资源
    最近更新 更多