2017/06/06

[c/c++]たぶん構造体メンバをvolatileにしても有効(弱気)

タイトルが弱気だが、致し方ない。


何がしたかったかというと、pthread_create()で動かしているスレッドでwhile()させてぐるぐる動かしている状態を、外部から止めたかったのだ。

スレッドで、whileで、変数監視となると、volatileになる。
普段はグローバル変数で監視させていたのだが、今回はスレッドをぽこぽこ作るようにしていたので、各スレッドが使う変数を構造体でまとめて初期値で与えつつ、そのままスレッドと共有する領域として使おうという計画だ。
おじさんはね、OSを使ったプログラムに慣れていないので、他に方法が思いつかなかったのだ。


その構造体の中に、ループを制御するための変数を持とうと思ったが、ちょっと迷った。
volatileって、構造体のメンバに指定しても反映してくれるのだろうか?


こういうときは、環境依存になってもよいから実験するに限る。


#include <stdio.h>

struct vol {
    int     abc;
    volatile int     def;
} volvol;


int main(void)
{
    while (volvol.def) {
        ;
    }
    return 0;
}

$ gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

こんな環境で試した。
なお、Ubuntuは16.04で、VirtualBox上で動かしている。
コンパイルはこのようにして、O2で最適化してアセンブラ出力させた。

$ gcc -O2 -o vol.S -S vol.c


まず、volatileありの場合。

	.file	"vol.c"
	.section	.text.unlikely,"ax",@progbits
.LCOLDB0:
	.section	.text.startup,"ax",@progbits
.LHOTB0:
	.p2align 4,,15
	.globl	main
	.type	main, @function
main:
.LFB23:
	.cfi_startproc
	.p2align 4,,10
	.p2align 3
.L2:
	movl	volvol+4(%rip), %eax
	testl	%eax, %eax
	jne	.L2
	rep ret
	.cfi_endproc
.LFE23:
	.size	main, .-main
	.section	.text.unlikely
.LCOLDE0:
	.section	.text.startup
.LHOTE0:
	.comm	volvol,8,8
	.ident	"GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609"
	.section	.note.GNU-stack,"",@progbits

ふーん。

次、volatile無しの場合。

	.file	"vol.c"
	.section	.text.unlikely,"ax",@progbits
.LCOLDB0:
	.section	.text.startup,"ax",@progbits
.LHOTB0:
	.p2align 4,,15
	.globl	main
	.type	main, @function
main:
.LFB23:
	.cfi_startproc
	movl	volvol+4(%rip), %eax
	.p2align 4,,10
	.p2align 3
.L2:
	testl	%eax, %eax
	jne	.L2
	rep ret
	.cfi_endproc
.LFE23:
	.size	main, .-main
	.section	.text.unlikely
.LCOLDE0:
	.section	.text.startup
.LHOTE0:
	.comm	volvol,8,8
	.ident	"GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609"
	.section	.note.GNU-stack,"",@progbits


差分は、ここ。
左がvolatileありで、右がvolatileなしだ。

image

L2ラベルでループしていて、volatileありはmovlがループ内に、volatile無しはmovlがループ外になった。

効いてる! 効いてるんだ!!


まあ、そもそもなんでvolatileが効かないかもしれないと思ったのか、という気もしてくる。
単に不安になっただけだ。
そういうことってあるだろう?


そういえば、gccとかって中間言語に吐き出してからリンカに掛けるとかだったから、アセンブラで安心するのは早いかもしれん。。。
いや、さすがにそこまでは疑わなくてもよいか。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。