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

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

解決済みの質問

スレッド間の送受信のコードについて

下記のコードは、(以前お教え頂きました)『synchronized』を使用した、スレッド間の
送受信のコードですが、その代わりに、Interruptとか、Thread.sleep()を使用した、
コードに変更してみたいと思います。

Q1)そのコードをお教え頂けないでしょうか?

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) {
}
}
}
}
以上

投稿日時 - 2015-07-20 10:30:23

QNo.9015578

困ってます

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

Q2
私の環境ではそのままコピペして動作させたもので72.5μsでした
genInterupt start
Cyclle time[us] T1=72.5
Cyclle time[ms] T2=0.0725
End of job

Q4)
私の環境は
Mac OS X Yosemite
Eclipse Mars Release (4.5.0)
JDK 1.8.0_45
です

投稿日時 - 2015-07-27 11:08:25

お礼

OKTara-さま

くどくど、質問して御免なさい。
ご回答有難うございます。

丁寧なご回答有難うございました。
下記のコードの20を2000に変更して、cycle_timeは42us位になりました。
(既にお送りしましたコードから、多少変更しているかもしれません。)
for(int i=0; i<20; i++){
H[ptrW]=T_threadC.DATAX++;
ptrW++;
if(ptrW>=T_threadC.CNT){
ptrW=T_threadC.CNT-1;
}
}

投稿日時 - 2015-07-27 19:20:23

ANo.4

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

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

回答(4)

ANo.3

Q1)この変更コードで受信漏れは、無いものと考えて宜しいでしょうか?
現状のコードのままであればほ確実に無いと思います。
動作環境の高負荷でThread.sleepの1秒が経過してしまったとかそういうケースは考えられますが、普通にはまずないと思ってよいと思います。

Q2)rcvInterruptに於ける受信を確認を確認することなく、送信側でDATAXの値を0から
  19999に順次カウントアップしまして、その都度target.interrupt()で割込みを掛ける
  方法はありますでしょうか?
イマイチイメージが出来ないのですが、T_threadC.transferedを使わずにとかそういう事でしょうか?

Q3)コードの旨くない所があれば、ご指摘頂けますと大変有り難いです。
以上、お手数ですが宜しくお願いします。
動作としては問題ないと思います。
ただ不要になったコメントアウトしているコードは消したり、使わない変数は消したり、冗長な記述は減らしたり、ネーミングを一般的な規約に合わせるとか、そういう細かい部分は気を配った方がいいかなと思います。他人とソースをやりとりする際にスムーズになります。
仕事だとめっちゃ怒られる事もあります。
知り合いは半角スペース一個余分に多かった事で反省文書かされたと言ってました

投稿日時 - 2015-07-24 15:38:33

補足

OKTaro-さま
毎度、お世話になります。

Q2)の質問の件
 質問のあと、自分なりにコードを考えていました(下記の添付をご覧ください)。
 コメント頂けますと大変有難いです。
 コンソール出力部分を2箇所コメント化しまして、サイクル時間は約770us程度でした。
 この値は遅い感じですね、何処かに不具合があるかもしれません。

>仕事だとめっちゃ怒られる事もあります。
知り合いは半角スペース一個余分に多かった事で反省文書かされたと言ってました
<---企業ですから、そうゆう事も必要かも知れませんね?

Q4)私のjavaの開発環境は、Windows7+EclipseのPleiades44です。
  もし出来れば貴方の、timerの時間が略正確だったと言われていました、
  環境を教えて頂けないでしょうか?

次は余談です。
日本で電子産業が何とか維持できているのは、ドコモが国産品のchipを使用しているからかも
知れません。日本の半導体は、価格と先進性の点で外国に太刀打ちできないようです。
私はARMプロセッサー(LPC1831)のシステムを開発したことがありますが、半導体は全て
欧米製とならざるを得ませんでした。お気に触りましたら、御免なさい。

東芝では無いですが、企業の上層部の出来ることは、社員に発破を掛ける
ことかも知れませんね?

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

import javax.swing.Timer;

class T_threadC {
static int CNT=20000;
volatile static int DATAX=-1;
public static void main(String args[]) {
new rcvInterrupt().start();
}
}

class genInterrupt extends Thread implements ActionListener{ //class rcvInterruptより起動される
public static Timer timer;
private Thread target;
volatile static int ptrW=0;
volatile static int ptrR=0;
volatile static int H[]=new int[T_threadC.CNT];


genInterrupt(rcvInterrupt targetx) {

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

public void actionPerformed(ActionEvent e){
timer.stop();
//一度に20個のデーターを作成しているわけは、タイマーの割込み時間は長く、Debug時間を短縮するためです。
//実際のAppに於きましては、USBの読込み(readBulk)を使用していますので、0.6ms強で割込みが発生します。
for(int i=0; i<20; i++){
H[ptrW]=T_threadC.DATAX++;
ptrW++;
if(ptrW>=T_threadC.CNT){
ptrW=T_threadC.CNT-1;
}
}
// System.out.println("================actionPerformed ptrW="+ptrW); //コメント化
timer.start();
}

public void run() {
System.out.println("genInterupt start");
// rcvInterruptが終了するまで繰り返す
while (target.isAlive()) {
// Thread.sleepで停止していたらinterrupt
if (target.getState() == Thread.State.TIMED_WAITING){
if(ptrW!=ptrR){
target.interrupt();
ptrR++;
}
}//if (target.getState() == Thread.State.TIMED_WAITING){
}//while (target.isAlive()) {
System.out.println("End of job");
System.exit(0);//**************************
}//public void run() {

}//class genInterrupt extends Thread {

class rcvInterrupt extends Thread {
// volatile boolean isWaited;
int ii;
public void run() {
new genInterrupt(this).start();//genInterruptを起動
System.out.println("=============new genInterrupt(this).start()");
long start=System.currentTimeMillis();
for (int i = 0; i <T_threadC.CNT; i++) {
try {
sleep(1000);
} catch (InterruptedException e1) {
// System.out.println("get interrupt cnt=" + i+" H="+genInterrupt.H[i]); //コメント化
}
}//for
long end=System.currentTimeMillis();
double T1=(double)(end-start)*1000.0/(double)T_threadC.CNT;
double T2=(double)(end-start)/(double)T_threadC.CNT;;
System.out.println("Cyclle time[us] T1="+T1);
System.out.println("Cyclle time[ms] T2="+T2);
}//public void run() {
}//class rcvInterrupt extends Thread {
以上、宜しくお願いします。

投稿日時 - 2015-07-24 21:08:58

ANo.2

以前の質問のお礼にありましたタイマーの件についてお答えします

まず私の環境では一度もinterruptされる事なく処理がループしていました。
原因は以下です
int ptrR = 0;
int ptrW = 0;

この2つの変数に対して
volatile int ptrR = 0;
volatile int ptrW = 0;

このようにvolatile修飾子をつける必要があります。
2つの異なるスレッドで同じ変数を参照する場合にこの修飾子をつけないと、値を正しく参照しない場合があります。

これをつけた結果、私の環境ではTimerはほぼ1ms間隔で処理を行っていました。

100msになってしまうと言っていた原因として考えられるのは
・volatile修飾子がついていないので、値の変更に気づけず無駄にループを繰り返していた
・単純に動作環境のスペックの問題
のどちらかだと思います。

投稿日時 - 2015-07-23 17:44:04

補足

OKTaro-さま
timerの件、回答有難うございます。
タイマーの精度につきましては、諦めて居た所ですが、volatile修飾子をつけまして
再度トライしてみます。

以上

投稿日時 - 2015-07-23 19:05:27

お礼

OKTaro- さま

毎度、お世話になります。
volatile属性をつけてトラーしましたが、やはり1msのタイマーが100ms位掛かっている
様です。

私の環境は、タイマーに関しまして、問題があるような感じです。
つまり、タイマーのcheckプログラムでも同様に旨く行きませんでしたが、
1msが100msになるような、酷い物では有りませんでした。

・単純に動作環境のスペックの問題 <---ご指摘のこれかも知れません

以上

投稿日時 - 2015-07-23 20:58:05

ANo.1

とりあえずポーリングしてsleep中であればinterruptするのであればこんな感じで

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

class genInterrupt extends Thread {
private Thread target;

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

public void run() {
System.out.println("genInterupt start");
// rcvInterruptが終了するまで繰り返す
while (target.isAlive()) {
// Thread.sleepで停止していたらinterrupt
if (target.getState() == Thread.State.TIMED_WAITING)
target.interrupt();
}
}
}

class rcvInterrupt extends Thread {
volatile boolean isWaited;

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

余談
先日は風邪を引いてしまい、放置になってしまいました。
あと、BA選ぶとクローズされてしまうので、回答者は追記が一切できなくなりますb

投稿日時 - 2015-07-23 12:00:50

補足

OKTaro-さま
ご返事、有難うございます。
貴方のご回答は、注意深く読ませて頂いております。
前回のsyncronozedの回答も、そのコードにバッファー関係を追加してみました。

今回の、ご回答も、勉強させて頂きます。

風邪をひかれたのことですが、体調管理には十分注意することが大切で、
油断とか過信が一番危険です。
以上

投稿日時 - 2015-07-23 14:57:03

お礼

OKTaro-さま
下記のコードは、rcvInterruptの受信を確認して、送信を行なう様に変更したものです。
20000回送信を行なってみましたが、受信漏れはありませんでした。
Q1)この変更コードで受信漏れは、無いものと考えて宜しいでしょうか?
Q2)rcvInterruptに於ける受信を確認を確認することなく、送信側でDATAXの値を0から
  19999に順次カウントアップしまして、その都度target.interrupt()で割込みを掛ける
  方法はありますでしょうか?
Q3)コードの旨くない所があれば、ご指摘頂けますと大変有り難いです。
以上、お手数ですが宜しくお願いします。

class T_threadC {
static int CNT=20000;
static int DATAX=-1;
static boolean transfered=true;
public static void main(String args[]) {
new rcvInterrupt().start();
}
}

class genInterrupt extends Thread { //class rcvInterruptより起動される
public static Object timer;
private Thread target;
genInterrupt(rcvInterrupt targetx) {
this.target = targetx;
}

public void run() {
System.out.println("genInterupt start");
// rcvInterruptが終了するまで繰り返す
while (target.isAlive()) {
// Thread.sleepで停止していたらinterrupt
if (target.getState() == Thread.State.TIMED_WAITING){
if(T_threadC.transfered==true){
T_threadC.transfered=false;
T_threadC.DATAX++;
target.interrupt();
// System.out.println("target.interrupt() DATAX="+T_threadC.DATAX);
}//if(T_threadC.transfered==true){
//target.interrupt();

}//if (target.getState() == Thread.State.TIMED_WAITING){
}//while (target.isAlive()) {
System.out.println("End of job");
System.exit(0);//**************************
}//public void run() {

}//class genInterrupt extends Thread {

class rcvInterrupt extends Thread {
// volatile boolean isWaited;
public void run() {
new genInterrupt(this).start();//genInterruptを起動
long start=System.currentTimeMillis();
for (int i = 0; i <T_threadC.CNT; i++) {
try {
sleep(1000);
} catch (InterruptedException e1) {
T_threadC.transfered=true;
System.out.println("get interrupt cnt=" + i+" DATAX="+T_threadC.DATAX);
}
}//for
long end=System.currentTimeMillis();
double T=(double)(end-start)*1000.0/(double)T_threadC.CNT;
System.out.println("Cyclle time[us] T="+T);
}//public void run() {
}//class rcvInterrupt extends Thread {

投稿日時 - 2015-07-23 18:59:54