• ベストアンサー

プログラムが3日目以降から調子が悪くなる

C言語を用いてある測定装置のデータを5秒おきに取得するプログラムを作成したのですが、3日11時間14分(61,128回目のループ)を過ぎると取得する時間が15秒後に一回になっていました。おそらくループが原因だと思うのですが自分で解決できなくて困っています。 ループの入り口は for(p=1;p<=loop;p++){ でpの型はlong型です。 5秒間に1つずつpの値は増えていくのですが、long型なので大きさは十分だと思います。 5秒間待つループは while((((clock()-start1)/ CLOCKS_PER_SEC ) % TIME )!= 0 ) { } // TIME=5 としてあり、start1には一番最初のループの前で取得した時間データが入っています。

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

  • ベストアンサー
  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.6

#3です。 もし、 for(p=1;p<=loop;p++){ ・・・・//ここの処理が必ず1秒超なら問題なし while(条件判定) { } で ・・・・の処理が1秒以内に完了することがあるなら、 ・・・の処理を1秒間に2回以上行う可能性があります。 これを排除したいなら(5秒間に1回だけ行いたいなら) 以下のようにすべきです。 time_t time0,time1; として time0 = time(NULL); for(){ ・・・・ while(1){ Sleep(1); time1 = time(NULL); if (time0 == time1) continue; if ((time1%TIME)!= 0) continue; time0 = time1; } } 考え方は、前回実行した時間(単位:秒)と同じなら、変わるまでスリープする。そして、5の倍数になるまで、スリープする。 になります。

xyz203
質問者

お礼

回答有難うございます。 time(NULL)で動作させてみたところちゃんと動きました!

その他の回答 (7)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.8

えぇと.... インターバルタイマじゃダメなんでしょうか? 「一定時間間隔で何かしたい」というなら最初の選択肢のような気がするんですが.

xyz203
質問者

お礼

回答ありがとうございます。 皆様のおかけで何とかできそうです。ありがとうございます。

  • chie65535
  • ベストアンサー率43% (8516/19358)
回答No.7

>OSの環境はwindowsでvisual stdio 2005を使用しています。 どの回答の方法も「% TIME」の式を使っている限り、処理されずに取りこぼす可能性がある。 もし「仮想メモリのスワップ動作で、1秒間以上、ディスクアクセスが続く」と言う状況で、その「1秒間」が「ほげほげ % TIME の式が 0 になる1秒間」であったら、取りこぼしが起き、計測は10秒に1回になる。 基本的に「5秒に1回計測する処理で、5秒待つのが間違い」である。 じゃ「5秒待たずに、どうすんの」かと言うと「待たないのが正解」なのだ。 つまり「5秒待ったりせず、常に時計の監視を続け、前回の計測時刻から、5秒以上経ってたら、次の計測をする」って事。ここで重要なのが「常に時計の監視を続けている」という事と「5秒以上の判断」という部分。 特に重要なのが「5秒以上」である。「5秒きっかり」ではないので「6秒後でも、7秒後でも計測する」ので、誰かにCPUを専有されていても大丈夫なのだ。 以下の3つの「時間経過の図」を見てほしい。どれも「開始してからの20秒間」の図である。 記号の意味 ■:計測処理している時間 □:待ち合わせしている時間 _:OSや他のタスクにCPUが専有された時間 ・単純に「5秒待つ」場合(□が5個になるまで待つ) ⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒ ■■□□_□□□■■_□□□□□■_□□ 20秒に3回しか実行されず、明らかに正しくない。 ・「% TIME」を用いて5で割った余りが0になるまで待つ場合 ⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒ ■■□□_■■□□□_□□□□■□_□□ ちょっと見には正しそうだが、3回目の計測タイミングで「他のタスクに処理を奪われ、5で割った余りが0になる秒が、過ぎてしまった」ので、20秒間に3回しか計測されていない。 ・「前回の計測から5秒以上経過したか」で処理した場合 ⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒ ■■□□_■■□□□_■■□□■□_□□ 3回目の計測は「期待した瞬間」よりも1秒遅れて「前回の計測から6秒後に開始」されているが、取りこぼしされるよりはマシであるので、このパターンが「最適」と言える。 つまり、以下のようにプログラムすべき。 -------------------- #define TIME 5L //time_t型は「typedef long time_t」と仮定する //なので、単純に加算、比較が可能と仮定する time_t next; //最初だけ「秒が変わるまで待つ」こと。 //じゃないと「秒が変わる寸前に最初の時刻を拾ってしまう」と //最初が「4秒間隔」になってしまう。 time(&next); while (next == time(&NULL)) {  Sleep(10); } //秒が変わったばかりの「フレッシュな現在時刻」を拾う time(&next); next += TIME; //ループ毎に「(p > loop)」の判定はしない for(p = 1;;) {  //「次の計測タイミングになったか、過ぎた場合」と言う事が重要  if (time(NULL) >= next) {   //「次の計測タイミング」を更新する   next += TIME;   //終了判定の「(p > loop)」は「pが変化した時のみ」で良い   if (++p > loop) break;   //計測を行う   keisoku();   continue;  }  //要は「秒が変わったか?」が重要なので「0.2秒間隔」など  //充分に長いインターバルで構わない  Sleep(200); //0.2秒待つ。 } -------------------- 上記の処理では「次に計測すべき時刻を5秒づつ進めているだけ」で「5秒待つ」とか「5で割った余りが0になる」などの「愚かな判定方法」は使用していない。 従って、タイミングに多少の前後はあっても「必ず、5秒に1回は、計測ルーチンを呼ぶ」のが保証される。

xyz203
質問者

お礼

回答有難うございます。 図を使った説明で大変分かりやすかったです。 データの取りこぼしは大変痛いのでこんな考え方があるのかと参考になりました。

  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.5

#3です。 windowsなら、 while((time(NULL)%TIME)!=0){ Sleep(1); //1ミリ秒スリープ } としてみて下さい。 尚、time()はtime(NULL)の誤りでした。失礼しました。 http://msdn.microsoft.com/ja-jp/library/1f4c8f33(VS.80).aspx

参考URL:
http://msdn.microsoft.com/ja-jp/library/cc429358.aspx
  • php504
  • ベストアンサー率42% (926/2160)
回答No.4

ずっと動かしていたらいつかclock( )がオーバーフローします

xyz203
質問者

お礼

回答ありがとうございます。 どうやらclock()が原因のようです。

  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.3

OSが提示されていないので、linux 32ビット環境の前提で、コメントしします。clock()関数の戻り値は、システム起動後、約72分で、clocl_t型の最大値(unsigned longの最大値)に達します。最大に達した後は、0に戻り、そこから増え続けます。従って、約72分ごとに、同じ値が戻ることになります。 従って、((clock()-start1)が(正しい意味で)意味があるのは、システム起動後の72分までの間ということになります。 また、 ((clock()-start1)が負の値になることも予想されます。 従って、5秒間に1回を実現したいのであれば、 while((time()%TIME)!=0){ } とすべきです。time()の場合は、32ビットマシンでも2030年程度まではオーバーフローしませんので使用可能です。 但し、#2の方が述べているように、sleepを一切行っていないのは、非常に問題のある使い方です。 正確に5秒のインタバルを保証したいのか、それとも5秒スリープ後に計測すればかまわないのかの何れかにより、対応の方法も異なりますが、いずれにせよ、sleep,usleep,nanosleeepのいずれかを使用すべきです。 http://www.linux.or.jp/JM/html/LDP_man-pages/man2/time.2.html http://www.linux.or.jp/JM/html/LDP_man-pages/man3/usleep.3.html http://www.linux.or.jp/JM/html/LDP_man-ges/man2/nanosleep.2.html

参考URL:
http://www.linux.or.jp/JM/html/LDP_man-pages/man3/clock.3.html
xyz203
質問者

お礼

回答ありがとうございます。 OSの環境はwindowsでvisual stdio 2005を使用しています。 どうやら、clock()関数がまずかったようですね。 計測は5秒間ごとにデータを取得することで、5秒スリープ後の計測ではないです。ですので、Sleep(5000)とするのは駄目でした。 >>while((time()%TIME)!=0){ この関数が使えそうですがtime()は引数が足りなくて駄目でしたので、もう一工夫してみようと思います。ありがとうございました。

  • nda23
  • ベストアンサー率54% (777/1415)
回答No.2

特殊な組込みといった環境なのでしょうか? 通常のアプリケーションの環境なら、「5秒待つ」はsleep関数を使う 方法を考えるべきです。「自力のループで待機」というのはCPUの タイムスライスからみると、とても「もったいない」使い方です。 あくまで、一般論です。OSが特殊な場合(sleep対応できない)も あります。 この場合はタイマー割り込みの回数を数える等の方法があります。

xyz203
質問者

お礼

回答ありがとうございます。 >>特殊な組込みといった環境なのでしょうか? OSはwindowsでVISA関数という変わった関数を使っていますが、これが特殊な組み込みなのかは私には勉強不足で分からないです。 >>「自力のループで待機」というのはCPUのタイムスライスからみると、とても「もったいない」使い方です。 おっしゃるとおり、CPU使用率が常に80%~100%になっておりどうしたらいいか困っておりました。また、プログラムの調子が良いときは80%~100%を行ったりきたりしてたのですが、プログラムの調子が悪いときは0%~100%とCPU使用率が変化していたのでひょっとしたら「自力のループで待機」がよくなかったかもしれません。 一度sleep関数を使って様子を見てみようと思います。ありがとうございました。

  • usatan2
  • ベストアンサー率37% (163/436)
回答No.1

自信はありませんが、 >start1には一番最初のループの前で取得した時間データが入っています。 これがまずいのではないですか? ループの直前に取得すれば問題が回避されると思います。

xyz203
質問者

お礼

回答ありがとうございます。 私の文章の書き方が悪くてすいません。ループの直前に取得してあります。

関連するQ&A

  • 一定周期実行プログラム

    UNIX環境での、プログラムを一定周期実行させるプログラミング方法についてご教授下さい。 例えば、50msの周期で、無限ループするプログラムです。 while(1) { t1=clock(); (処理1); t2=clock(); passtime=(t2-t1)/CLOCKS_PER_SEC; time=0.05-passtime; tmp=(int)(1000000*time); usleep(tmp); } まず、思い付いたプログラムは、処理1に掛かった時間を計算し、50msから処理に掛かった時間を引いた時間をsleepで待たせるプログラムです。clock()は精度が低いようですが・・・他に何かいい方法はないでしょうか?

  • 秒数を数える(C言語)

    プログラム実行時に時間を数え始めて、100秒経過したらまた最初からプログラムを実行しようと考えています。(tcpdumpみたいなもの) まず、秒数を数えて出力するプログラムを作ってみたのですが、実行しても0.000000と出てしまい、数えることが出来ませんでした。 (例) #include<stdio.h> #include<time.h> void tekitou(); int main() { while(1) { /*無限ループ*/ tekitou(); } return 0; } void tekitou() { static time_t start; time_t last; start = clock(); last = clock(); printf("%f\n", (double)(last - start)/CLOCKS_PER_SEC); } OSはLinuxでコンパイラはgccです。よろしくおねがいします。

  • 時間を経過させる関数

    この関数は引数xに1000を渡すと1秒の経過をさせる 関数です。 int sleep(unsigned long x) { clock_t c1 = clock(),c2; do { if((c2 = clock()) == (clock_t)-1) return 0; }while(1000.0*(c2-c1)/CLOCKS_PER_SEC<x); return 1; } 質問は3つです。 (1) if((c2 = clock()) == (clock_t)-1) return 0; ・clock()を呼び出し、その結果をc2に代入する。c2が-1だったら、returnする。返却値は0を返す。 つまり、時間の経過中にエラーが起きたら値を返すというものです。 質問としては、「(clock_t)-1」の意味です。「clock_t型から-1を引く?」なぜ-1と等しいのでしょうか? (2) while(1000.0*(c2-c1)/CLOCKS_PER_SEC<x); この文なのですが、なぜc2からc1を引く理由としては ・c1は関数を呼び出した時点の時間であり0秒固定。 ・c2に関しては「上記の不等式が不成立になるまで経過する時間」 と考えてよろしかったでしょうか? (3) また、上記の文の不等式の右辺のxは単位がミリ秒なので、不成立になるには、不等 式の左側は「関数呼び出しから現在までの経過時間(ミリ秒)」になるはずです。 左辺は最初に(c2-c1)を1000倍をしてそこからCLOCKS_PER_SECという 一秒あたりのクロック数(1000)を割っているのでc2やc1は最初から ミリ秒の単位がclock()で渡されるということなのでしょうか? お手数ですがよろしくお願いします。

  • clock関数を利用した時間計測法について

    以下のソースコードについての質問です。 --- /* 文字列を1文字ずつ表示して後ろから1文字ずつ消去するのを繰り返す */ #include <time.h> #include <stdio.h> /*--- xミリ秒経過するのを待つ ---*/ int sleep(unsigned long x) { clock_t c1 = clock(), c2; do { if ((c2 = clock()) == (clock_t)-1) /* エラー */ return (0); } while (1000.0 * (c2 - c1) / CLOCKS_PER_SEC < x); return (1); } --- このコード中の while (1000.0 * (c2 - c1) / CLOCKS_PER_SEC < x); の箇所で、整数の 1000 ではなく、実数の 1000.0 を使う意味(メリット)は オーバーフロー対策の他に何かありますか? ありましたら教えてください。 また、整数の1000に比べ実数の1000.0を含む計算(浮動小数点演算)に 極端に時間がかかる環境の場合、 実数を使う方がsleep関数の精度が劣るデメリットがあると思いますが、 その他に実数を使う場合のデメリットはありますか? ありましたら教えてください。 (コードにおいて、clock_t型はunsignedと同義の場合もあれば signed long intと同義の場合もあると思いますが、どれもありうる(処理系依存)と考えてください。 CLOCKS_PER_SECも1000や1000000の場合もあると思いますが、どれもありうる(処理系依存)と考えてください。)

  • clock関数は正確じゃないの?

    clock関数で時間を計測するとどうも狂ってしまいます。 おかしいので、このようなプログラムでclock関数の精度を調べてみました。 #include <stdio.h> #include <time.h> int main(){     int i,j;     clock_t start;     for(i=0;i<50;i++){         start = clock();         for(j=0;j<3000000000;j++);         printf("%4.3f秒\n",(double)(clock()-start)/CLOCKS_PER_SEC);         }     return 0; } このプログラムの実行結果はこちらです。 1.672秒 1.672秒 1.672秒 1.672秒 1.687秒←● 1.672秒 1.672秒 1.672秒 1.672秒 1.672秒 1.671秒 1.672秒 1.672秒 1.672秒 1.688秒←● ・・(略) 若干1.672で落ち着いているかと思いきや、時々狂っています。 この狂いは何が原因なんでしょうか? しかも狂うときは0.01位、結構ガツンと狂います。 しかもその狂い←●が等間隔で現れるのかと思いきや、そうでもありません。 この一見そろっているようで、時々ガツンと狂うのは何故なんでしょうか?

  • clock関数での経過時間計測

    clock関数でプログラムの時間を計測しようと思っているのですがうまくいきません。 ----------------------------- clock_t start,end; start = clock(); (処理) end = clock(); printf("かかった時間:%f",(double)(end-start)/CLOCKS_PER_SEC); ----------------------------- 上のようにしているのですが、実行結果は0.00000秒と出てしまいます。処理のところは足し算を何題か出題し解答を入力し正解したら次の問題というようなことをしています。 確認のためstartにclock()を代入した後とendに代入したあとでprintfでstartとendを出力してみましたが、どちらの値も10.00000で同じ値となっています。0秒になるのはこれのせいだと思うのですが、どうして同じ値になるのでしょうか?

  • clock()関数の誤差

    プログラムの実行時間の計測について質問させていただきます。 現在,実行時間の計測でclock()関数を使っているのですが誤差が出ます。 timeコマンド(と実際に時計で測った時間)では95分、clock()関数で測った プログラム全体の実行時間は1376秒(約23分)と誤差が出る状態にあります。 プログラムでclock()関数を使っているのはmain()だけです。 printf()内がおかしいのでしょうか? 詳しい方、回答よろしくおねがいします。 ↓プログラム #include<time.h> (中略) clock_t t1,t2,t3,t4; (中略) main() { struct zahyo P,Q; int a,b,prime,Ord,sec; scanf("%d",&a); (中略) printf("Q.y = "); scanf("%d",&Q.y); t1=clock(); Ord=OrdCal(P,a,prime); t2=clock(); printf("Ord = %d\n",Ord); printf("OrdCal:%f(s)\n",(double)(t2-t1)/CLOCKS_PER_SEC); t3=clock(); PohlingBsgs(P,Q,a,prime,Ord); sec=secretkey(); t4=clock(); printf("secretkey=%d\n",sec); printf("Decipher:%f(s)\n",(double)(t4-t3)/CLOCKS_PER_SEC); printf("Total :%f(s)\n",(double)(t4-t1)/CLOCKS_PER_SEC); } 実行結果 Ordcal:74.170000(s) Decipher:1302.722704(s) Total :1376.902104(s) real 94m33.445s user 94m30.900s sys 0m0.980s

  • 素因数分解のプログラムを作成しました。

    素因数分解のプログラムを作成しました。 なぜか11桁を超えた場合、正しく表示されません!! アドバイス等お願いします。 あと、処理時間も組んでみましたがこちらもうまくいきません。 改善をお願いしますm(_ _)m #include<stdio.h> #include<time.h> void fanction(int); void main(void) { int n; clock_t start_time, end_time; printf("整数を入力してください。\n"); scanf("%d",&n); start_time = clock(); fanction(n); end_time = clock(); printf("\n\n処理時間:%.3f秒\n",(double)(end_time - start_time) / CLOCKS_PER_SEC); return 0; } void fanction(int n) { int m; char c='='; for(m=2;n != 1;m++) { while(n%m == 0) { n = n/m; printf("%c%d",c,m); c='*'; } } }

  • 4桁の英字の3桁目を当てるプログラム

    乱数でとってくる4ケタの英字の3桁目を入力して当てるプログラムを 組もうとしているのですが、コンパイラしてもいまいちうまくいきません。 特に下に書いたプログラムのこの部分が違っていると思い どのように修正したらよいのか指摘していただきたいです。 human=getchar(); if(comp[2]!=human) { ero=1; } よろしくお願いします。 #include<stdio.h> #include<stdlib.h> #include<time.h> #include<string.h> int sleep(unsigned long x) { clock_t c1=clock(),c2; do{ if((c2=clock())==(clock_t)-1) { return 0; } }while(1000.0*(c2-c1)/CLOCKS_PER_SEC<x); return 1; } int main(void) { int num,val,i,j; char comp[21]; char human; int ero=0; int try_count=0; int seikai=0; clock_t start,end; int num1; char eiji[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ"; srand(time(NULL)); puts("英字記憶トレーニング"); do{ printf("挑戦するレベル(3~20):"); scanf("%d",&num1); }while(num1<3 || num1>20); printf("%d個の英字を記録しましょう。\n",num1); start=clock(); do{ for(i=0;i<num1;i++) { comp[i]=eiji[rand()%strlen(eiji)]; } comp[num1]='\0'; printf("%s",comp); fflush(stdout); sleep(125*num1); printf("\r%*s\r3番目の英字を入力してください:",num1,""); human=getchar(); if(comp[2]!=human) { ero=1; } if(ero==0) { printf("正解です。\n"); seikai++; } else { printf("\a間違いです。\n"); } try_count++; }while(try_count<2); end=clock(); printf("%d回中%d回成功しました。\n",try_count,seikai); printf("%.1f秒でした。\n",(double)(end-start)/CLOCKS_PER_SEC); return 0; }

  • clock_gettime()について

    clock_gettime()について質問です。 http://kazmax.zpp.jp/cmd/c/clock_getres.3.html にある、 「関数 clock_gettime ()は、指定されたクロック clk_id の時間を取得する。」 という説明が理解できないのです。 分解能は理解できます。 "クロックの時間"とは何をさすのでしょうか? 1クロックあたりが何秒かということでしょうか? 1クロックが何秒に相当するのか、何ナノ秒に相当するのかが メンバtv_secとtv_nsecにそれぞれ格納されるのでしょうか? struct timespec { time_t tv_sec; /* 秒 */ long tv_nsec; /* ナノ秒 */ }; ご教示ください。

専門家に質問してみよう