[openrtm-users 01239] サービスポートにおけるデータの受信について

4 posts / 0 new
Last post
root
Offline
Last seen: 4 days 19 hours ago
Joined: 2009-06-23 14:31
[openrtm-users 01239] サービスポートにおけるデータの受信について

OpenRTM MLの皆様

筑波大学の木村と申します。

プロバイダ側からコンシューマ側へ構造体ポインタを渡す際に
Segmantation fault となってしまいデータを送ることが
できないのですが、解決方法をご存じの方がいらっしゃいましたら
ご教示お願いいたします。

今年度からubuntu8.04にてOpenaRTM-aist-1.0を利用しており、
現在、下記のようなidlファイルを用いてサービスポートを
作成中なのですが、下記のimpl.cppファイルの様な内容を記述し、
プロバイダ側からコンシューマ側へ構造体ポインタを
渡す際にプロバイダ側でSegmantation fault となってしまいデータを送ることが
できない状況にあります。

過去のメーリングリスト [openrtm-users 00795] にて類似の質問に対する
解決策を見つけたのですが、本件では、下記のidlファイル内容を
変更することなく用いたいと考えております。

勉強不足で、至らない点も多々あるかとは思いますが、ご教示して
頂けたら幸いです。

以下に再現用のテストで用いたidlファイル、およびimpl.cppファイル内の該当
部を記します。
---ここから(idlファイル)---
module RTC
{
struct RETURN_ID
{
long id;
string comment;
};
};
interface ManipulatorCommonInterface_Common
{
RTC::RETURN_ID clearAlarms();
};
---ここまで(idlファイル)---

---ここから(impl.cppファイル)---
RTC::RETURN_ID* ManipulatorCommonInterface_CommonSVC_impl::clearAlarms()
{
RTC::RETURN_ID* retval;
retval->id = 0;
retval->comment="OK";
return retval;
}
---ここまで(impl.cppファイル)---

Undefined
root
Offline
Last seen: 4 days 19 hours ago
Joined: 2009-06-23 14:31
[openrtm-users 01240] サービスポートにおけるデータの受信について

筑波大 木村様

産総研 安藤です

> OpenRTM MLの皆様
>
> 筑波大学の木村と申します。
>
> プロバイダ側からコンシューマ側へ構造体ポインタを渡す際に
> Segmantation fault となってしまいデータを送ることが
> できないのですが、解決方法をご存じの方がいらっしゃいましたら
> ご教示お願いいたします。
>
>
> 今年度からubuntu8.04にてOpenaRTM-aist-1.0を利用しており、
> 現在、下記のようなidlファイルを用いてサービスポートを
> 作成中なのですが、下記のimpl.cppファイルの様な内容を記述し、
> プロバイダ側からコンシューマ側へ構造体ポインタを
> 渡す際にプロバイダ側でSegmantation fault となってしまいデータを送ることが
> できない状況にあります。
>
> 過去のメーリングリスト [openrtm-users 00795] にて類似の質問に対する
> 解決策を見つけたのですが、本件では、下記のidlファイル内容を
> 変更することなく用いたいと考えております。
>
> 勉強不足で、至らない点も多々あるかとは思いますが、ご教示して
> 頂けたら幸いです。
>
> 以下に再現用のテストで用いたidlファイル、およびimpl.cppファイル内の該当
> 部を記します。
> ---ここから(idlファイル)---
> module RTC
> {
> struct RETURN_ID
> {
> long id;
> string comment;
> };
> };
> interface ManipulatorCommonInterface_Common
> {
> RTC::RETURN_ID clearAlarms();
> };
> ---ここまで(idlファイル)---
>
> ---ここから(impl.cppファイル)---
> RTC::RETURN_ID* ManipulatorCommonInterface_CommonSVC_impl::clearAlarms()
> {
> RTC::RETURN_ID* retval;
> retval->id = 0;
> retval->comment="OK";
> return retval;
> }
> ---ここまで(impl.cppファイル)---

RTC::RETURN_ID* ManipulatorCommonInterface_CommonSVC_impl::clearAlarms()
{
RTC::RETURN_ID* retval = new RTC::RETURN_ID();
retval->id = 0;
retval->comment = CORBA::String_dup("OK");
return retval;
}

こうするとどうなりますでしょうか?

解説:
・宣言したRETURN_IDのポインタに、領域を確保せずに使用しようと
 しているので Segmentation Fault が発生します。ですので、newで
 確保する必要があります。
・CORBAの引数の受け渡し規則で、「returnした構造体など複雑なデータ型
 は、returnした先で自動的に開放される」、というのがあります。
 したがって、関数内でnewして領域を確保しても、return後にちゃんと
 解放されますので、deleteしなくても大丈夫です。

あと、好みの問題ですが、RETURN_ID のようにすべて大文字だと、
マクロと混同する人もいるので、構造体であれば ReturnID 等のよう
な書き方のほうがよいと思います。

root
Offline
Last seen: 4 days 19 hours ago
Joined: 2009-06-23 14:31
[openrtm-users 01241] サービスポートにおけるデータの受信について

筑波大 木村様

産総研 安藤です

先ほど送ったコードで、String_dup とありましたが、string_dupの間違いです。
説明するのを忘れてましたが、文字列を構造体のメンバーに格納する際には、
コピーしてあげる必要がありますので、

retval->comment = CORBA::string_dup("OK");

のようにstring_dupを使用してコピーしてあげます。

また、構造体やオブジェクトでは _var型という一種のスマートポインタ
が自動的に宣言され、利用できます。

今回のコードも_var型を利用すると以下のように書けます。

RTC::RETURN_ID* ManipulatorCommonInterface_CommonSVC_impl::clearAlarms()
{
RTC::RETURN_ID_var retval = new RTC::RETURN_ID();
retval->id = 0;
retval->comment = CORBA::String_dup("OK");
return retval._retn();
}

このケースでは、あまりありがたみが分かりにくいのですね。

CORBAに限らずC++では通常、new で領域を確保した構造体やオブジェクトは、
必ずどこかで delete する必要があります。

void Hoge_impl::hoge_func()
{
MyObject* obj = new MyObject();
// obj を使って何かをする。... (1)
delete obj;
}

この例では、関数の終わりでdeleteを読んで、newした領域を解放しています。
しかし、最後の delete obj がないと、この関数が呼ばれるたびに
領域を確保だけして解放しないため、どんどんメモリを食いつぶしていきます。
#所謂、メモリリークです。

しかし、delete obj があってもメモリリークするケースがあります。
それは、(1) の部分で例外が発生した場合です。この場合、delete obj は
呼ばれず、リークしてしまいます。また、関数内でreturnが複数ある場合は
delete を気をつけて配置しなければなりませんし、書き忘れることもあります。

そういうときに利用するのがスマートポインタと呼ばれるものです。
C++ の標準では STL の auto_ptr などがありますし、boost や C++の
新しい仕様 (C++0x)では shared_ptr など色々なスマートポインタを標準で利用可能です。
#これらはC++一般の話なので詳しくは本やWeb等を参照してください。

CORBAは非常に古い規格で、こうしたスマートポインタが一般的でない
ころから存在しており、またその他複雑な事情で、独自にスマートポインタを
持っています。それが_var 型と呼ばれるものです。

_var 型は以下のように、delete を明示的に書かなくても、スコープ(関数の一番下の括弧)
を抜けると、自動的にnewで確保した領域を解放してくれます。

void Hoge_impl::hoge_func()
{
MyObject_var obj = new MyObject();
// obj を使って何かをする。... (1)
// delete obj; しなくても、スコープを抜けると自動で解放してくれる。
}

最初の話に戻りますが、今回の木村さんのclearAlarms関数では、
return 後に領域を解放されると困ります。(returnしたRETURN_ID構造体は
CORBAが相手にデータを渡すまで、データを保持しなければならないから。)
_var はデフォルトでは スコープを抜けると領域を解放しますが、
CORBAでは、return でデータを返した後は、CORBA (ORB) がデータを
相手に送った後で、自動的に開放することになっています。
_retn() はそういうときに使用する関数で、領域の自動解放を行わないで
return した先にゆだねる時に呼びます。

RTC::RETURN_ID* ManipulatorCommonInterface_CommonSVC_impl::clearAlarms()
{
RTC::RETURN_ID_var retval = new RTC::RETURN_ID();
retval->id = 0;
retval->comment = CORBA::String_dup("OK");
return retval._retn(); // メモリの解放は return した先にゆだねる
} // retval の領域は解放されない

結局は、前のメールにおいて生のポインタに対して new して delete せずに
return するのと大して変わりはないのですが、第3者がこの関数をみれば
関数内でnew しているのに、delete していないのを見て「あれ?」と思い、
もしバグを探している最中なら、この関数内でdeleteすべきか、あるいは
return先でちゃんとメモリが解放されているかを調べ回ると思います。

しかし_var 型ポインタを利用することでCORBAのオブジェクトや構造体で
あることが明確になりますし、_retn() を呼ぶことで、return した先に領域の
解放を任せていることが明確になります。また、_var 型には、(IDLの)in/out/inout
それぞれの型の引数に値を渡すための in(), out(), inout() といったメンバー
関数も用意されているので、それぞれのケースにおいて、領域の解放をそれぞれ
自分がやるべきなのか、任せるべきなのかを考えなくても、_retn(), in(), out(), inout()
関数を呼んでやるだけでよいようになっています。

void Foo::foo_func()
{
Hoge_var hoge0 = munya0->getHoge();
munya1->setHoge(hoge0.in()); // IDL で setHoge(in Hoge data) のように宣言されている
munya2->processHoge(hoge0.inout()); // IDL で setHoge(in Hoge data)
のように宣言されている

Hoge_var hoge1;
bar0->getHoge(hoge.out()); // bar0->getHoge() はHogeの領域を確保しそれを hoge1にセットして返す。
}

CORBAのその他の変数受け渡し規則については、こちらをご覧ください。
http://www.openrtm.org/OpenRTM-aist/html/CORBA2FE5A489E695B0E58F97E6B8A1E8A68FE58987.html

こちら等も参考になるかと思います。
http://otndnld.oracle.co.jp/document/products/tuxedo/tux80j/cref/member.htm

>
>> OpenRTM MLの皆様
>>
>> 筑波大学の木村と申します。
>>
>> プロバイダ側からコンシューマ側へ構造体ポインタを渡す際に
>> Segmantation fault となってしまいデータを送ることが
>> できないのですが、解決方法をご存じの方がいらっしゃいましたら
>> ご教示お願いいたします。
>>
>>
>> 今年度からubuntu8.04にてOpenaRTM-aist-1.0を利用しており、
>> 現在、下記のようなidlファイルを用いてサービスポートを
>> 作成中なのですが、下記のimpl.cppファイルの様な内容を記述し、
>> プロバイダ側からコンシューマ側へ構造体ポインタを
>> 渡す際にプロバイダ側でSegmantation fault となってしまいデータを送ることが
>> できない状況にあります。
>>
>> 過去のメーリングリスト [openrtm-users 00795] にて類似の質問に対する
>> 解決策を見つけたのですが、本件では、下記のidlファイル内容を
>> 変更することなく用いたいと考えております。
>>
>> 勉強不足で、至らない点も多々あるかとは思いますが、ご教示して
>> 頂けたら幸いです。
>>
>> 以下に再現用のテストで用いたidlファイル、およびimpl.cppファイル内の該当
>> 部を記します。
>> ---ここから(idlファイル)---
>> module RTC
>> {
>> struct RETURN_ID
>> {
>> long id;
>> string comment;
>> };
>> };
>> interface ManipulatorCommonInterface_Common
>> {
>> RTC::RETURN_ID clearAlarms();
>> };
>> ---ここまで(idlファイル)---
>>
>> ---ここから(impl.cppファイル)---
>> RTC::RETURN_ID* ManipulatorCommonInterface_CommonSVC_impl::clearAlarms()
>> {
>> RTC::RETURN_ID* retval;
>> retval->id = 0;
>> retval->comment="OK";
>> return retval;
>> }
>> ---ここまで(impl.cppファイル)---
>
> RTC::RETURN_ID* ManipulatorCommonInterface_CommonSVC_impl::clearAlarms()
> {
> RTC::RETURN_ID* retval = new RTC::RETURN_ID();
> retval->id = 0;
> retval->comment = CORBA::String_dup("OK");
> return retval;
> }
>
> こうするとどうなりますでしょうか?
>
> 解説:
> ・宣言したRETURN_IDのポインタに、領域を確保せずに使用しようと
> しているので Segmentation Fault が発生します。ですので、newで
> 確保する必要があります。
> ・CORBAの引数の受け渡し規則で、「returnした構造体など複雑なデータ型
> は、returnした先で自動的に開放される」、というのがあります。
> したがって、関数内でnewして領域を確保しても、return後にちゃんと
> 解放されますので、deleteしなくても大丈夫です。
>
> あと、好みの問題ですが、RETURN_ID のようにすべて大文字だと、
> マクロと混同する人もいるので、構造体であれば ReturnID 等のよう
> な書き方のほうがよいと思います。
>
>

root
Offline
Last seen: 4 days 19 hours ago
Joined: 2009-06-23 14:31
[openrtm-users 01242] サービスポートにおけるデータの受信について

産総研 安藤様

筑波大 木村です。

ご教示していただきありがとうございます。
ご指摘して頂いた様にソースの方を書き換えましたところ
無事データのやり取りを行うことができました。
結果、説明して頂いたように、ポインタの領域を確保して
いなかったことが問題だったようです。

また、ソースのご指摘のみならず、メモリ・ポインタ等についても
懇切丁寧にご説明していただき大変勉強になりました。
重ねて御礼申し上げます。

(2010/05/24 15:01), Ando Noriaki wrote:
> 筑波大 木村様
>
> 産総研 安藤です
>
> 先ほど送ったコードで、String_dup とありましたが、string_dupの間違いです。
> 説明するのを忘れてましたが、文字列を構造体のメンバーに格納する際には、
> コピーしてあげる必要がありますので、
>
> retval->comment = CORBA::string_dup("OK");
>
> のようにstring_dupを使用してコピーしてあげます。
>
>
> また、構造体やオブジェクトでは _var型という一種のスマートポインタ
> が自動的に宣言され、利用できます。
>
> 今回のコードも_var型を利用すると以下のように書けます。
>
> RTC::RETURN_ID* ManipulatorCommonInterface_CommonSVC_impl::clearAlarms()
> {
> RTC::RETURN_ID_var retval = new RTC::RETURN_ID();
> retval->id = 0;
> retval->comment = CORBA::String_dup("OK");
> return retval._retn();
> }
>
> このケースでは、あまりありがたみが分かりにくいのですね。
>
> CORBAに限らずC++では通常、new で領域を確保した構造体やオブジェクトは、
> 必ずどこかで delete する必要があります。
>
> void Hoge_impl::hoge_func()
> {
> MyObject* obj = new MyObject();
> // obj を使って何かをする。... (1)
> delete obj;
> }
>
> この例では、関数の終わりでdeleteを読んで、newした領域を解放しています。
> しかし、最後の delete obj がないと、この関数が呼ばれるたびに
> 領域を確保だけして解放しないため、どんどんメモリを食いつぶしていきます。
> #所謂、メモリリークです。
>
> しかし、delete obj があってもメモリリークするケースがあります。
> それは、(1) の部分で例外が発生した場合です。この場合、delete obj は
> 呼ばれず、リークしてしまいます。また、関数内でreturnが複数ある場合は
> delete を気をつけて配置しなければなりませんし、書き忘れることもあります。
>
> そういうときに利用するのがスマートポインタと呼ばれるものです。
> C++ の標準では STL の auto_ptr などがありますし、boost や C++の
> 新しい仕様 (C++0x)では shared_ptr など色々なスマートポインタを標準で利用可能です。
> #これらはC++一般の話なので詳しくは本やWeb等を参照してください。
>
> CORBAは非常に古い規格で、こうしたスマートポインタが一般的でない
> ころから存在しており、またその他複雑な事情で、独自にスマートポインタを
> 持っています。それが_var 型と呼ばれるものです。
>
> _var 型は以下のように、delete を明示的に書かなくても、スコープ(関数の一番下の括弧)
> を抜けると、自動的にnewで確保した領域を解放してくれます。
>
> void Hoge_impl::hoge_func()
> {
> MyObject_var obj = new MyObject();
> // obj を使って何かをする。... (1)
> // delete obj; しなくても、スコープを抜けると自動で解放してくれる。
> }
>
> 最初の話に戻りますが、今回の木村さんのclearAlarms関数では、
> return 後に領域を解放されると困ります。(returnしたRETURN_ID構造体は
> CORBAが相手にデータを渡すまで、データを保持しなければならないから。)
> _var はデフォルトでは スコープを抜けると領域を解放しますが、
> CORBAでは、return でデータを返した後は、CORBA (ORB) がデータを
> 相手に送った後で、自動的に開放することになっています。
> _retn() はそういうときに使用する関数で、領域の自動解放を行わないで
> return した先にゆだねる時に呼びます。
>
> RTC::RETURN_ID* ManipulatorCommonInterface_CommonSVC_impl::clearAlarms()
> {
> RTC::RETURN_ID_var retval = new RTC::RETURN_ID();
> retval->id = 0;
> retval->comment = CORBA::String_dup("OK");
> return retval._retn(); // メモリの解放は return した先にゆだねる
> } // retval の領域は解放されない
>
> 結局は、前のメールにおいて生のポインタに対して new して delete せずに
> return するのと大して変わりはないのですが、第3者がこの関数をみれば
> 関数内でnew しているのに、delete していないのを見て「あれ?」と思い、
> もしバグを探している最中なら、この関数内でdeleteすべきか、あるいは
> return先でちゃんとメモリが解放されているかを調べ回ると思います。
>
> しかし_var 型ポインタを利用することでCORBAのオブジェクトや構造体で
> あることが明確になりますし、_retn() を呼ぶことで、return した先に領域の
> 解放を任せていることが明確になります。また、_var 型には、(IDLの)in/out/inout
> それぞれの型の引数に値を渡すための in(), out(), inout() といったメンバー
> 関数も用意されているので、それぞれのケースにおいて、領域の解放をそれぞれ
> 自分がやるべきなのか、任せるべきなのかを考えなくても、_retn(), in(), out(), inout()
> 関数を呼んでやるだけでよいようになっています。
>
> void Foo::foo_func()
> {
> Hoge_var hoge0 = munya0->getHoge();
> munya1->setHoge(hoge0.in()); // IDL で setHoge(in Hoge data) のように宣言されている
> munya2->processHoge(hoge0.inout()); // IDL で setHoge(in Hoge data)
> のように宣言されている
>
> Hoge_var hoge1;
> bar0->getHoge(hoge.out()); // bar0->getHoge() はHogeの領域を確保しそれを hoge1にセットして返す。
> }
>
> CORBAのその他の変数受け渡し規則については、こちらをご覧ください。
> http://www.openrtm.org/OpenRTM-aist/html/CORBA2FE5A489E695B0E58F97E6B8A1E8A68FE58987.html
>
> こちら等も参考になるかと思います。
> http://otndnld.oracle.co.jp/document/products/tuxedo/tux80j/cref/member.htm
>
>
>
>>
>>> OpenRTM MLの皆様
>>>
>>> 筑波大学の木村と申します。
>>>
>>> プロバイダ側からコンシューマ側へ構造体ポインタを渡す際に
>>> Segmantation fault となってしまいデータを送ることが
>>> できないのですが、解決方法をご存じの方がいらっしゃいましたら
>>> ご教示お願いいたします。
>>>
>>>
>>> 今年度からubuntu8.04にてOpenaRTM-aist-1.0を利用しており、
>>> 現在、下記のようなidlファイルを用いてサービスポートを
>>> 作成中なのですが、下記のimpl.cppファイルの様な内容を記述し、
>>> プロバイダ側からコンシューマ側へ構造体ポインタを
>>> 渡す際にプロバイダ側でSegmantation fault となってしまいデータを送ることが
>>> できない状況にあります。
>>>
>>> 過去のメーリングリスト [openrtm-users 00795] にて類似の質問に対する
>>> 解決策を見つけたのですが、本件では、下記のidlファイル内容を
>>> 変更することなく用いたいと考えております。
>>>
>>> 勉強不足で、至らない点も多々あるかとは思いますが、ご教示して
>>> 頂けたら幸いです。
>>>
>>> 以下に再現用のテストで用いたidlファイル、およびimpl.cppファイル内の該当
>>> 部を記します。
>>> ---ここから(idlファイル)---
>>> module RTC
>>> {
>>> struct RETURN_ID
>>> {
>>> long id;
>>> string comment;
>>> };
>>> };
>>> interface ManipulatorCommonInterface_Common
>>> {
>>> RTC::RETURN_ID clearAlarms();
>>> };
>>> ---ここまで(idlファイル)---
>>>
>>> ---ここから(impl.cppファイル)---
>>> RTC::RETURN_ID* ManipulatorCommonInterface_CommonSVC_impl::clearAlarms()
>>> {
>>> RTC::RETURN_ID* retval;
>>> retval->id = 0;
>>> retval->comment="OK";
>>> return retval;
>>> }
>>> ---ここまで(impl.cppファイル)---
>>>
>> RTC::RETURN_ID* ManipulatorCommonInterface_CommonSVC_impl::clearAlarms()
>> {
>> RTC::RETURN_ID* retval = new RTC::RETURN_ID();
>> retval->id = 0;
>> retval->comment = CORBA::String_dup("OK");
>> return retval;
>> }
>>
>> こうするとどうなりますでしょうか?
>>
>> 解説:
>> ・宣言したRETURN_IDのポインタに、領域を確保せずに使用しようと
>> しているので Segmentation Fault が発生します。ですので、newで
>> 確保する必要があります。
>> ・CORBAの引数の受け渡し規則で、「returnした構造体など複雑なデータ型
>> は、returnした先で自動的に開放される」、というのがあります。
>> したがって、関数内でnewして領域を確保しても、return後にちゃんと
>> 解放されますので、deleteしなくても大丈夫です。
>>
>> あと、好みの問題ですが、RETURN_ID のようにすべて大文字だと、
>> マクロと混同する人もいるので、構造体であれば ReturnID 等のよう
>> な書き方のほうがよいと思います。
>>

Log in or register to post comments

Download

latest Releases : 2.0.0-RELESE

2.0.0-RELESE Download page

Number of Projects

Choreonoid

Motion editor/Dynamics simulator

OpenHRP3

Dynamics simulator

OpenRTP

Integrated Development Platform

AIST RTC collection

RT-Components collection by AIST

TORK

Tokyo Opensource Robotics Association

DAQ-Middleware

Middleware for DAQ (Data Aquisition) by KEK