みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

javaの割込みのcatchに関する質問

下記のコードはgenInterruptにて、割込みを10回発生させ、rcvInterruptでその
割込みをcatchするものです。

割込みの発生周期が1msの場合は、割込みのcatchは略10回受取ることが出来ますが、
割込みの発生周期が短い場合は、最初の2、3個受取るのみです。
Q1)割込みの発生周期が1msの場合には、全ての割込みをcatchすることが出来ますか?

//==========================
//Project: Interrupt(受信側セット)の確認
class T_thread extends Thread{
static int TIMES=20;
public static void main(String args[]){
rcvInterrupt obj=new rcvInterrupt();
obj.start();
for (int i = 0 ; i <TIMES ; i++){
try{
Thread.sleep(1);
//System.out.println("main: "+TIMES+"20回の1msタイマー待ち");
}catch(InterruptedException e){
}
}
}
}

class genInterrupt extends T_thread{
private Thread target;
genInterrupt(Thread targetx){
this.target=targetx;
}
public void run(){
System.out.println("genInterupt start");
for (int i=0; i<10; i++){
try{
Thread.sleep(0); //割込みが殆ど捕らえられない
//Thread.sleep(1); //割込みが全て捕らえられない事がたまにある
target.interrupt();
}
catch(InterruptedException e){
}
}
}
}

class rcvInterrupt extends T_thread{
int cnt=0;
public void run(){
genInterrupt obj=new genInterrupt(Thread.currentThread());
obj.setPriority(Thread.MAX_PRIORITY);

obj.start();
System.out.println("receiveInterupt start");
for (int i=0 ; i<20 ; i++){
try{
Thread.sleep(2);
}catch(InterruptedException e){
System.out.println("get interrupt cnt="+cnt++);
}
}
}
}
//==========================
以上、宜しくお願いします。

投稿日時 - 2015-07-12 20:46:14

QNo.9011159

困ってます

質問者が選んだベストアンサー

このコードでは実行時の状況に左右されますので、発生周期いくつにしたら10回インタラプトされるという事は保証できません。
とはいっても最近のPCの性能ではそこまでブレはでませんが…
ただ、上記のコードでは保証はされない、という事です。

絶対に大丈夫という保証をつけるのであればsynchronizedなどを用いて、キチンと同期処理を実装して意図した順番でコードが動作するようにする必要があります。

投稿日時 - 2015-07-13 15:42:02

補足

明快な回答有難うございます。
>絶対に大丈夫という保証をつけるのであればsynchronizedなどを用いて、キチンと同期処理を実装して意図した順番でコードが動作するようにする必要があります。

<--もし、出来ればsynchronizedをどの様に使用すれば良いのでしょうか?

投稿日時 - 2015-07-14 07:30:15

お礼

OKTaro-さま
毎度、お世話になります。
貴方に教えて頂きましたコードに、Timerにより1ms毎に割込みを発生するルーチンをgenInterruptに実装しまし、このタイマー動作に同期しましてgenInterruptが割込みを
発生し、rcvInterrptがその割込みを受信する様に考えました。
下記のコードをご覧ください。
タイマーの割込み動作が遅く1msではなく、100ms毎に割込みを発生する様なかんじです。
この件に、関しまして、コメント頂けますと大変助かります。

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.Timer;

class T_thread {
public static void main(String args[]) {
new rcvInterrupt().start();
}
}

class genInterrupt extends Thread implements ActionListener{
static int CNT=2048;
static int INDEX=0;
static Timer timer;
int H[]=new int[1024];
int ptrR=0;
int ptrW=0;
private rcvInterrupt target;

genInterrupt(rcvInterrupt targetx) {
this.target = targetx;
timer = new Timer(1 , this);
timer.start();
}

public void actionPerformed(ActionEvent e){
if(ptrW<1000000) {
H[ptrW++]=ptrW;
ptrW&=1023;
H[ptrW++]=ptrW;
ptrW&=1023;
System.out.println("================actionPerformed ptrW="+ptrW);
}
}

public void run() {
System.out.println("genInterupt start");
// for (int i = 0; i <CNT; i++) {
while(CNT>0){
if(ptrW>ptrR){
//=========================
//受信側が、wait()状態になった事を確認して、notifyAll()を実行する
while (!target.isWaited) {//isWaitedがtrueになるのを待つ
// rcvInterruptがsynchronizedブロックに入るまで待ち合わせ
// これがないと連続してsynchronizedしてしまう可能性がある
}
synchronized (target) {
target.notifyAll();//notifyAllにより、wait()を抜け出る
target.isWaited = false;//
// System.out.println("===notify in genInterrupt");
}//synchronized (target) {
//=========================
ptrR++;
ptrR&=1023;
CNT--;
INDEX++;
}
else if(ptrR>ptrW){
while (!target.isWaited) {//isWaitedがtrueになるのを待つ
}
synchronized (target) {
target.notifyAll();//notifyAllにより、wait()を抜け出る
target.isWaited = false;//
// System.out.println("===notify in genInterrupt");
}//synchronized (target) {
ptrR++;
ptrR&=1023;
CNT--;
INDEX++;
}
// } //for
}
}// public void run() {
}//class genInterrupt extends Thread {

class rcvInterrupt extends Thread {
int CNTX=2048;
volatile boolean isWaited;

//=========================
public synchronized void run() {
new genInterrupt(this).start();
System.out.println("=============new genInterrupt(this).start()");
for (int i = 0; i <CNTX; i++) {
try {
isWaited = true;
wait();//notifyAllにより、rcvInterruptのwait()を抜け出る
//isWaitedはfalseになる
System.out.println("get interrupt i=" + i+" CNT="+genInterrupt.INDEX);
//isWaited = true;
}
catch (InterruptedException e1) {
}
}//for
System.out.println("==========End of rcvInterrupt");
genInterrupt.timer.stop();
System.exit(0);//**************************
}//public synchronized void run() {
//=================================
}//class rcvInterrupt extends Thread {

投稿日時 - 2015-07-15 16:18:17

ANo.1

このQ&Aは役に立ちましたか?

1人が「このQ&Aが役に立った」と投票しています

回答(4)

ANo.4

>Q2)下記の2つのコードで、rcvInterruptにthisをてけるとstaticに付きエラーになりますが、

についてですが、まず2つのエラーになりえる要因があります。

mainメソッド内で
new rcvInterrupt().start();
をコールしていると思いますが、これはご推察の通り、staticメソッド内ですので、this参照が出来ずにエラーになります。これが1つ

仮にthisの参照(T_threadクラスのインスタンス)が渡せたとしても
new rcvInterrupt(this).start();
というコードはエラーになります。これが2つ目
これが
>new genInterrupt(this).start()にthisが必要な訳は何でしょうか?
というところに関わってきます。

new クラス名

のコードで呼び出されるのはnewしようとしているクラスのコンストラクタがコールされます。
rcvInterruptクラスにはコンストラクタが宣言されていないのですが、一つもコンストラクタがない場合は引数がないコンストラクタがあるものと等価になります。

public rcvInterrupt() {
}

というものがあるものとして動くという理解で問題ありません。
new rcvInterrupt();では上記のコンストラクタをコールしますので、何か引数を渡した場合、エラーになるのです。

一方genInterruptクラスでは

genInterrupt(rcvInterrupt targetx) {
this.target = targetx;
}

というコンストラクタが宣言されていますので、rcvInterruptクラスのインスタンスを渡さないとエラーになるのです。
冗長な記述ですが、以下のように書き換えると繋がりがわかりやすいかもしれません。
rcvInterrupt Interrupt = this;
new genInterrupt(Interrupt).start();


簡潔に言いますと
「genInterruptクラスのコンストラクタの引数にrcvInterruptのインスタンスが必要だから」
が答えになります

投稿日時 - 2015-07-14 16:50:20

補足

OKTaro- さま

明確、親切な回答有難うございます。

投稿日時 - 2015-07-14 21:09:59

お礼

OKTaro- さま

毎度、お世話になります。
もし、出来れば、貴方に教えて頂きました最初のコードに下記の機能の追加が出来ないでしょうか?
1)1Kワード(型int)のリングバッファーを設けまして、1msに2ワードの割合でバッファーに
書き込みを行ないます。
 0x1、0x2,0x3,......0x1024,0x1025,0x1024......
0番地          最後    0番地
2)バッファーに未送信のデーターがあり、受信側が受信可能ならば、送信を行ないます。

お手数ですが、もし出来れば、お願いします。
貴方に教えて頂きました、notifyAllを使用するコードは私にとりましては、新しい方式であり
本当に参考になりました。
以上

投稿日時 - 2015-07-15 07:39:17

ANo.3

>Q1) クラスT_threadの中に、 CNTと CNTXを下記の如く追加しまして、rcvInterruptとgenInterruptの繰返しに反映させるためには、どの様に変更すれば宜しいでしょうか?

一般的には定数と呼ばれる宣言時に値を固定したものを使用します。
今回は他のクラスから参照する定数になるので、可視性をpublicにしたものを宣言します。
public : 可視性を全ての範囲にする
static : 静的アクセス。インスタンスを必要としない
final : 一度しか初期化出来なくする

class T_thread {
public static final int CNT = 2000;
public static final int CNTX = CNT;
// 以下略
}

という定数を用意しまして

使用するクラスからは
for (int i = 0; i < T_thread.CNT; i++)
for (int i = 0; i < T_thread.CNTX; i++)

のように参照します。
static修飾子が付いているので、「クラス名.変数名」という形でアクセス出来ます。
元の質問のソースのTIMESという変数でもT_thread.TIMESと書けば参照できるはずです。

※通常大文字とアンダースコアだけで構成された変数名は定数として扱うのが普通なので、static final をつけるのが良いと思います。その他、いろいろ命名規則がありますので、その辺も見ておくと他の人とコードをやりとりする際にスムーズになると思います。

投稿日時 - 2015-07-14 15:50:09

補足

OKTaro- さま
初歩的な質問の回答有難うございます。
貴方の回答を、よく読み理解いたします。
ついでに、もし出来れば、もう一つ教えて頂けないでしょうか?
Q2)下記の2つのコードで、rcvInterruptにthisをてけるとstaticに付きエラーになりますが、
new genInterrupt(this).start()にthisが必要な訳は何でしょうか?
 ====================
 new rcvInterrupt().start();
 new genInterrupt(this).start();
=====================
注)貴方のプログラムの割込みの送信とその受信の部分に関しましては、
これから勉強させて頂きます。
今までの、不安が解消しまして、所謂目から鱗が落ちた感です。

以上

投稿日時 - 2015-07-14 16:26:53

お礼

OKTaro- さま
毎度、お世話になります。
先に質問しました、thisの件は、多少わかりました。
即ち、割込み信号の受信先を、送信元のgenInterruptに知らせるためと思います。
========================
genInterrupt(rcvInterrupt targetx) {
this.target = targetx;
}
========================

notiyAll()について、これから勉強します。

以上

投稿日時 - 2015-07-14 16:48:52

ANo.2

synchronizedを使ってマルチスレッド処理の順番制を保証する場合はThread.sleepではなく、Object.waitとObject.notify(またはnotifyAll)を使用するのが良いと思います。
というのもwaitとnotifyは「待ち合わせ」を行う事ができますが、Thread.sleepでは「一方的に一時停止」するだけだからです。

waitとnotifyを使うとすると以下のようなコードであれば確実に順番を保証できます。

class T_thread {
public static void main(String args[]) {
new rcvInterrupt().start();
}
}

class genInterrupt extends Thread {
private rcvInterrupt target;

genInterrupt(rcvInterrupt targetx) {
this.target = targetx;
}

public void run() {
System.out.println("genInterupt start");
for (int i = 0; i < 10; i++) {
while (!target.isWaited) {
// rcvInterruptがsynchronizedブロックに入るまで待ち合わせ
// これがないと連続してsynchronizedしてしまう可能性がある
}
synchronized (target) {
target.notifyAll();
target.isWaited = false;
System.out.println("notify");
}
}
}
}

class rcvInterrupt extends Thread {
volatile boolean isWaited;

public synchronized void run() {
new genInterrupt(this).start();
for (int i = 0; i < 10; i++) {
try {
isWaited = true;
wait();
System.out.println("get interrupt cnt=" + i);
} catch (InterruptedException e1) {
}
}
}
}

※補足
メソッドにsynchronizedをつけた場合はsynchronized(this)でメソッド全体の処理を括った時と動き的には等価です(バイトコードは異なり、メソッド宣言につけた方が軽量です)
なお、staticメソッドの宣言につけて場合はsynchronized(クラス.class)と等価です。
synchronizedブロックにはひとつのスレッドしか入ることが出来ないというルールを利用したコードになります。synchronizedブロック内でwaitをコールするとスレッドを停止させた状態でsynchronizedの進入する権利を開放します。それによってもう片方のスレッドがsynchronizedブロックに入り、notifyAllをコールし、waitしているスレッドを起こします。
notifyAllをコールしたあとsynchronizedブロックを抜ける事により、waitから起こされたスレッドが再び起動します。以上!

※オマケ
Thread.sleepを使うとすると、軽く考えた感じでは一時停止の用途に合わない処理を実現しようとしているので、多分めんどくさいことになります。
Thread.sleepでないと意味がないんだ!という場合は…考えてみます

投稿日時 - 2015-07-14 09:54:25

補足

OKTaro-様
先ほど、お礼コメントで、最初の基本的な質問(これはthread以前の質問です)を
しましたが、下記の如くT_thread を変更し、genInterruptクラスとrcvInterruptクラスをstatic
に変更しました所、旨く行きました。
御免なさい、初歩的な質問をしまして。
==================
class T_thread {
static int CNT=20000;
static int CNTX=CNT;
public static void main(String args[]) {
//rcvInterrupt obj=new rcvInterrupt();
//obj.start();
new rcvInterrupt().start();
}
//} //この括弧をコードの最後に移動

//=====================

投稿日時 - 2015-07-14 15:42:20

お礼

OKTaro-様
早速の、素晴らしい回答有難うございます。
10回の繰返しの所を2000に変更しましてRunしました所、約2秒で終了しました。
(注、私のsyncronizedを使用したプログラムは、約20秒以上の実行時間が掛かりました)
貴方のプログラムの、内容は未だ私には不明ですので、これから勉強します。
手元にある本は、わかりやすいjavaオブジェクト指向(川場隆著)であり、ITの
記事も読んでいますが、未だ初心者です。

最初の基本的な質問(これはthread以前の質問です)
Q1) クラスT_threadの中に、 CNTと CNTXを下記の如く追加しまして、rcvInterruptとgenInterruptの繰返しに反映させるためには、どの様に変更すれば宜しいでしょうか?
現在は、クラスrcvInterruptとgenInterruptの中に、個別に記載しています。
class T_thread {
  int CNT=2000;
int CNTX=CNT;
public static void main(String args[]) {
new rcvInterrupt().start();
}
}

この変更後、ソースを弄り、勉強の予定です。
以上

投稿日時 - 2015-07-14 15:12:56

あなたにオススメの質問