27570
GTK+で使われているらしい、GIOchannelを使って、IOの入力をイベントドリブンで受けようとしています。  
<https://tech-blog.cerevo.com/archives/254/>  
↑こちらのサイトなどを参考にさせて頂いて、イベント自体は問題なく受けることがですが、

一度イベントを受けると一定期間イベントをスルーしたいと考えています。  
この為には、librtを使ってタイマー割り込みを使えば良いかと思います。  
ただ、単純にGIOchannelのコールバック関数内でtimer_create()、timer_settime()した場合、  
タイマー関連の変数は、static変数にするべきかと思うんですが、コールバック関数自体が  
static関数になっています。

この場合、static変数を使うべきなのでしょうか？

よろしく、お願い致します。
CC BY-SA 3.0
2016-07-12T05:48:33.110
27558
2016-07-13T22:21:46.703
15090
question
c
static関数
質問の内容とは違ってきますが、GIOChannelを使うのであれば、タイマーもGLibの物を使ってはいかがですか?

  * [g_timeout_add_full](https://developer.gnome.org/glib/2.48/glib-The-Main-Event-Loop.html#g-timeout-add-full)

以下、timer_createは使った事がないので、自信なし。

「man timer_create」を見ると、以下のようなサンプルが載っていたのですが。

```

           sev.sigev_notify = SIGEV_SIGNAL;
           sev.sigev_signo = SIG;
           sev.sigev_value.sival_ptr = &timerid;
           if (timer_create(CLOCKID, &sev, &timerid) == -1)
               errExit("timer_create");
    
```

こんな感じで、sival_ptrに「タイマ関連の変数」とやらを渡せませんかね?  
いや、本当に自信ないです。間違っていたらごめんなさい。

* * *

> g_timeout_add_fullは定期的なファンクションの実行で、希望の動作とは‌​違いような気がします。

確かにg_timeout_add_fullは一定時間間隔で **繰り返し** ファンクションを実行 **できる** APIですが、
**繰り返し実行しなければならない** なんて决まりはありません。  
よく一定時間後に処理を起こすためにも使いますよ。

例えば、以下はボタンが押されたらボタンを使用不可にし(ついでにラベルも変更し)、3秒後に元に戻すプログラムです。

```

    #include <gtk/gtk.h>
    #include <glib.h>
    
    #define NUM_BUTTONS 1
    
    static gboolean on_timeout(gpointer user_data)
    {
        gtk_button_set_label(GTK_BUTTON(user_data), "Push");
        gtk_widget_set_sensitive(GTK_WIDGET(user_data), TRUE);
        /* ここでTRUEを返すとまた3秒後に呼ばれるが、FALSEを返すとこれ以上呼ばれない */
        return FALSE;
    }
    
    static void on_clicked(GtkButton *button, gpointer user_data)
    {
        gtk_button_set_label(button, "Sleeping...");
        gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
        g_timeout_add_full(G_PRIORITY_DEFAULT, 3000, on_timeout, button, NULL);
    }
    
    int main(int argc, char *argv[])
    {
        GtkWidget *window;
        GtkWidget *button;
        GtkWidget *box;
        int i;
    
        gtk_init(&argc, &argv);
    
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        gtk_window_set_default_size(GTK_WINDOW(window), 128, -1);
        box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
        gtk_container_add(GTK_CONTAINER(window), box);
        for (i = 0; i < NUM_BUTTONS; ++i) {
            button = gtk_button_new_with_label("Push");
            gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
            g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(on_clicked), NULL);
        }
    
        g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
        gtk_widget_show_all(window);
        gtk_main();
        return 0;
    }
    
```

* * *

で、「g_timeout_add_fullを使えばいいじゃん」で思考が止まっていたので、質問内容をよく理解せず、間違った解釈をしてしまったのですが、読みなおしてみると申し訳ないがちょっと意味が読み取れませんでした。  
一応、static変数の使い方について疑問を持っているのかな、と感じましたので、そのあたりを説明します。

C言語のstatic変数は、スコープ制限のついたグローバル変数という扱いになります。  
そして、グローバル変数を多用するとソースコードが読みにくくなる傾向があります。

  * [変数の使い方: グローバル変数](http://homepage1.nifty.com/~takaot/prprpr/vargene.html#GLOBAL)

static変数の使用がグローバル変数のそれとすべて一緒だとは言えませんが、コールバックの引数として渡さず、static変数を介して渡すのは、上のサイトの言葉を借りれば
**「ルーチン・モジュールの独立性を損なうやり方」** だと思います。

例えば、上のプログラム。  
static変数を使ってコールバックを呼ぶこともできます。

```

    static GtkButton *s_button;
    
    static gboolean on_timeout(gpointer user_data)
    {
        gtk_button_set_label(s_button, "Push");
        gtk_widget_set_sensitive(GTK_WIDGET(s_button), TRUE);
        /* ここでTRUEを返すとまた3秒後に呼ばれるが、FALSEを返すとこれ以上呼ばれない */
        return FALSE;
    }
    
    static void on_clicked(GtkButton *button, gpointer user_data)
    {
        gtk_button_set_label(button, "Sleeping...");
        gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
    
        s_button = button;
        g_timeout_add_full(G_PRIORITY_DEFAULT, 3000, on_timeout, NULL, NULL);
    }
    
```

しかし、仕様変更でボタンが増えた場合は、どうしますか。  
いろいろと変更が必要になります。  
元のプログラムであれば、ボタンを増やすだけで済みます。コールバックの変更は必要ありません。(「NUM_BUTTONS」の値を変えるだけです。)

決して「static変数を使うな」とは言いませんが、それぞれのメリット・デメリットをしっかりと理解し、可読性のあるプログラミングを心がけることが大事だということを忘れないでください。

…んー、このような説明は苦手だ。理解できなかったら、ごめんなさい。

* * *

'16/7.14 追記  
(寝て起きたら、いいサンプルが思いついたので、書き直しました)
CC BY-SA 3.0
2016-07-12T13:29:16.730
27570
2016-07-13T22:21:46.703
2016-07-13T22:21:46.703
15473
15473
27558
answer