dbts2013 特濃jpoug log_file_sync

33
Copyright © 2013 Insight Technology, Inc. All Rights Reserved. Insight Technology, Inc. JPOUG (Japan Oracle User Group) 新久保 浩二 (@kouji_s_0808) OLTPにつける薬はあるのか? - log file sync の進化と謎 -

Upload: koji-shinkubo

Post on 27-Jan-2015

133 views

Category:

Documents


5 download

DESCRIPTION

 

TRANSCRIPT

Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

Insight Technology, Inc.JPOUG (Japan Oracle User Group)

新久保 浩二 (@kouji_s_0808)

OLTPにつける薬はあるのか? - log file sync の進化と謎 -

2Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

Who am I ?

1. データベース マニアック担当

2. Oracle ACE

3. JPOUG(Japan Oracle User Group)

(http://www.jpoug.org)

本資料に使用されている社名、ロゴ、製品、サービス名およびブランド名は、該当する各社の登録商標または商標です。本資料の一部あるいは全体について、許可なく複製および転載することを禁じます。

本資料の内容に関して、不適当な表現や検証が足りない部分もありますがご容赦ください。

3Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

COMMIT

用途

COMMIT文を使用すると、現行のトランザクションを終了し、トランザクションで

実行したすべての変更を確定できます。トランザクションとは、Oracle Databaseが

1つの単位として扱う一連のSQL文です。

また、この文によって、トランザクション内のセーブポイントがすべて消去され、

トランザクション・ロックが解除されます。

Database SQL言語リファレンスより

こ み っ と

4Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

本日の試み

本日は、日頃皆さんが何気なく実行するcommitを肴に、

「commitする人の気持ち」 と

「commitされる人の気持ち」

を堪能しようという試みです。

- commitの裏舞台では、どんな事がくりひろげられてるの?

- Oracleリリースが進んで、 commit関連の何かが変わったの?- 11gでは?

- 12cでは?

- 深まる謎?

とか (ちなみに、本資料の環境は主にLinux上でのお話です。)

5Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

OLTP系ベンチマークでよく見る風景

Commit クラス

6Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

具体的にはlog file sync

log file sync

7Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

いざ!!

8Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

$ ps -ef | grep sqlplus | grep –v greporacle 31699 31645 0 07:55 pts/1 00:00:00 sqlplus as sysdba

$ pstree -alp 31699sqlplus,31699 ¥040 as sysdba│└─ oracle,32567 (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))

$ ps -ef | grep lgwr | grep –v greporacle 31595 1 0 Nov02 ? 00:22:16 ora_lgwr_oracle11g

フォアグランド

SHADOWプロセス(commitする人)

LGWR(commitされる人)

今日の大事な点 その1 (プロセスの関係)

今日は、この人たちのsystem callを追いかけます。(latch等は追いかけません)

9Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

SEMCTL(2) Linux Programmer’s Manual SEMCTL(2)

名前semctl - セマフォの制御操作を行なう

書式#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>

int semctl(int semid, int semnum, int cmd, ...);

説明semctl() は、 semid で指定されたセマフォ集合 (semaphore set) またはセマフォ集合のsemnun 番目のセマフォに対して、 cmd で指定された制御操作を行なう (集合内のセマフ ォの番号は 0 から始まる)。

この関数は、 cmd の値に依存して、3 個または 4 個の引き数を持つ。引き数が 4 個の場合、第 4 引き数の型は union semun である。呼び出し元プログラムは、この共用体 (union)を以下のように定義しなければならない。

union semun {int val; /* SETVAL の値 */struct semid_ds *buf; /* IPC_STAT, IPC_SET 用のバッファ */unsigned short *array; /* GETALL, SETALL 用の配列 */struct seminfo *__buf; /* IPC_INFO 用のバッファ

(Linux 固有) */};

今日の大事な点 その2 (セマフォ)

SEMOP(2) Linux Programmer’s Manual SEMOP(2)

名前semop, semtimedop - セマフォの操作

書式#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>

int semop(int semid, struct sembuf *sops, unsigned nsops);

int semtimedop(int semid, struct sembuf *sops, unsigned nsops,struct timespec *timeout);

glibc 向けの機能検査マクロの要件 (feature_test_macros(7) 参照):

semtimedop(): _GNU_SOURCE

説明セマフォ集合 (semaphore set) のメンバーの各セマフォは以下の関連情報を持っている:

unsigned short semval; /* セマフォ値 */unsigned short semzcnt; /* ゼロを待つプロセス数 */unsigned short semncnt; /* 増加を待つプロセス数 */pid_t sempid; /* 最後に操作を行なったプロセス */

semop() は semid で指定されたセマフォ集合の選択されたセマフォに対して操作を行う。

semctl(2)他のプロセスを起こす

semtimedop(2)他のプロセスに起こされ

るまで寝る

10Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

一般的なcommit (11.2.0.4)

皆さんご存知のcommitの動作SHADOW PROCESS LGWR ------------------------------------------------------------------------------ ------------------------------------------------------------------15:56:52.451519 semtimedop(1802252, {{18, -1, 0}}, 1, {3, 0}) = -1 EAGAIN15:56:55.452866 semtimedop(1802252, {{18, -1, 0}}, 1, {3, 0}) = -1 EAGAIN15:56:58.454356 semtimedop(1802252, {{18, -1, 0}}, 1, {3, 0}) = 15:57:01.125824 update !15:57:01.129724 update complete15:57:01.181562 commit !15:57:01.184351 semctl(1802252, 18, SETVAL, 0x1) = 015:57:01.184939 io_submit(140400303636480, 2, {{0x7fb17c6a1480, 0, 1, 0, 267}, …}) = 215:57:01.185218 semtimedop(1802252, {{34, -1, 0}}, 1, {0, 100000000}) = 15:57:01.185558 io_getevents(140400303636480, 2, 128, {{0x7fb17c6a1480,…,{0,0}) = 215:57:01.185729 semctl(1802252, 34, SETVAL, 0x1) = 015:57:01.186277 semtimedop(1802252, {{18, -1, 0}}, 1, {0, 270000000}) = -1 EAGAIN15:57:01.186385 commit complete15:57:01.457908 semtimedop(1802252, {{18, -1, 0}}, 1, {3, 0} =

Shadow process

LGWR process

2789μ秒

588 μ秒 619 μ秒 171 μ秒

656 μ秒commit semctl semtimedop

commit complete

io_submit io_getevents semctl

semtimedop

log file sync

log file parallel write

多分、log file sync は shadowプロセスがsemtimedop(2)で眠ってから、LGWRに起こされて、commit完了を内部的に確認

できるまで

11Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

深まる謎 その1

プロセスの復帰に関して、OSのプロセス・スケジューラーの影響はあるのか?

Shadow process

LGWR process

2789μ秒

588 μ秒 619 μ秒 171 μ秒

656 μ秒commit semctl semtimedop

commit complete

io_submit io_getevents semctl

semtimedop

log file sync

log file parallel write

もし、影響があるとしたら、Linuxのタイマー割り込み分解性能ってHZ依存Tickで1msとか4msとか10msとかじゃなかった?

そうなると、環境によっては、残念なこともあるかもしれない?

12Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

深まる謎 その1 の考察

まず、RHEL5.6 (2.6.18-238.el5) と OEL6.4(2.6.39-400.209.1.el6uek.x86_64)で、nanosleep(2)で10回、1μ秒スリープしてみてOSのプロセス・スケジューラーによる遅延を確認してみる。

最近のOS(検証環境はOracle Linux 6.4 - UEK) だとTicklessカーネル&高精度タイマーになっていて、昔みたいにHZ依存のTickで世界が縛られることはなくなっているよう。

これだと、OSのバージョンで、相当OLTP性能へ影響が出てしまうはずだが、本当なのか?

56 55 55 55 54 55 54 55 61

1971 2005 1994 2007 1986 2000 21441860

1993

0

1,000

2,000

3,000

#1 #2 #3 #4 #5 #6 #7 #8 #9

μ秒

OS別割り込み分解性能

2.6.39-400.209.1.el6uek.x86_64 2.6.18.238.el5-x86_64

13Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

深まる謎 その1 の考察

ということで、簡単なセマフォのサンプルで試してみた。

正確にカーネルのソースは見てないですが、nanosleep(2)の場合はOSのプロセス・スケジューラーがタスク状態を変更して、セマフォ関連は、OSのプロセス・スケジューラーに非依存で実装されている模様(ここ、大事)

61

93 8960

8166 57

106

6046 58

45

185

53 45 48

131

45

0

100

200

#1 #2 #3 #4 #5 #6 #7 #8 #9

μ秒

セマフォでのWakeup時間の実測値

2.6.39-400.209.1.el6uek.x86_64 2.6.18.238.el5-x86_64

なので、セマフォを使ってcommitの状態のやり取りを行っている限り、OSのプロセス・スケジューラーの遅延は、そんなに気にならないくらい高速。(でも遅延 - log file sync - は無くならない)

14Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

余談

余談

15Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

(余談) commitする人にも事情はあるので

皆さんご存知のcommitのモードは大きく4つ

commitのモードは[IMMEDIATE] と BATCHcommitの待機モードは[WAIT] と NOWAIT

初期パラメーターで指定するなら10gの頃は

COMMIT_WRITE=“IMMEDIATE,WAIT” とか11g以降は

COMMIT_LOGGING=IMMEDIATECOMMIT_WAIT=WAIT とか

SQL単位で指定するならcommit write immediate wait; とか

皆さんご存知のPL/SQLのcommitのデフォルトモードはBATCH NOWAIT

❝ データベース初期化パラメータCOMMIT_LOGGINGおよびCOMMIT_WAITが設定されていない場合、非分散トランザクションに対するPL/SQLのデフォルトのコミット動作はBATCH NOWAITです。❞

PL/SQL言語リファレンス より

16Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

(余談) commitモードによる違い (11.2.0.4)

% time seconds usec/call calls errors syscall

7.50 0.000472 5 100 0 semtimedop

0.37 0.000023 0 100 0 semctl

PL/SQL immediate wait

PL/SQL batch wait

% time seconds usec/call calls errors syscall

0.00 0.00000 0 100 0 semtimedop

0.00 0.00000 0 100 0 semctl

PL/SQL で commit のモードを変えながら、100回update + commitを実行

17

% time seconds usec/call calls errors syscall

0.39 0.000023 0 100 0 semctl

0.00 0.000000 0 1 0 semtimedop

% time seconds usec/call calls errors syscall

0.00 0.000000 0 2 0 semctl

0.00 0.000000 0 1 0 semtimedop

% time Seconds usec/call calls errors syscall

0.00 0.000000 0 100 0 semctl

0.00 0.000000 0 1 0 semtimedop

Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

(余談) commitモードによる違い (11.2.0.4)

PL/SQL immediate nowait

PL/SQL batch nowait

PL/SQL commit (DEFAULT)

このケースだとPL/SQLで実行しているので(多分)PL/SQLブロックの抜ける際に、semctl(2)でLGWRを起こ

して、semtimedop(2)でlog bufferのフラッシュ完了を待っている。

普通のSQLだと、semtimedop(2)は実行されない。つまり、REDOログへの書き込みの正常性を全くチェック

しませんので、ご注意を!

さらに、semtimedop(2)で待たないので当然log file syncも(ほぼ)ない

です。

18Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

(余談) commitモードでの速度比較

ご参考までに

76.921 75.878

12.395 10.832 11.739

0

10

20

30

40

50

60

70

80

90

PL/SQL IMMEDIATE

WAIT

PL/SQL BATCH WAIT PL/SQL IMMEDIATE

NOWAIT

PL/SQL BATCH NOWAIT PL/SQL COMMIT

(DEFAULT)

Ela

psed

Tim

e(s

ec)

100,000 commits per every insert

commit mode comparison (11.2.0.4)

19Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

新種のcommit発見! (11.2.0.x)

20Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

新種のcommit発見! (11.2.0.4)

(少なくとも私は知らなかった)新種のcommitが出てきました!SHADOW PROCESS LGWR ------------------------------------------------------------------------------ ------------------------------------------------------------------12:04:11.936399 semtimedop(1802252, {{18, -1, 0}}, 1, {3, 0}) = -1 EAGAIN12:04:14.940066 semtimedop(1802252, {{18, -1, 0}}, 1, {3, 0}) = 12:04:16.385834 update !12:04:16.388814 update complete12:04:16.388954 commit !12:04:16.601262 semctl(1802252, 18, SETVAL, 0x1) = 012:04:16.601762 nanosleep({0, 466000}, 0x7fff24c2dc80) = 012:04:16.602330 io_submit(140400303636480, 2, {{…}}) = 212:04:16.602380 nanosleep({0, 466000}, 0x7fff24c2dc80) = 012:04:16.602995 nanosleep({0, 466000}, 0x7fff24c2dc80) = 012:04:16.603163 io_getevents(140400303636480, 2, 128,…,{0,0}) = 212:04:16.603724 semtimedop(1802252, {{18, -1, 0}}, 1, {1, 340000000}) = -1 EAGAIN12:04:16.604007 commit complete12:04:17.945345 semtimedop(1802252, {{18, -1, 0}}, 1, {3, 0}) = -1 EAGAIN

Shadow process

LGWR process

312.308ミリ秒

1068 μ秒

commit

log file sync

log file parallel write

semctl nanosleepnanosleepnanosleepcommit

complete

io_submit io_getevents semtimedop

500 μ秒 618 μ秒 615 μ秒 1012 μ秒

833 μ秒 561 μ秒

semtimedop(2)で眠るかわりに

nanosleep(2)で眠っている

semctl(2)で他のプロセスを起こす。ということはしない

21Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

post/wait と post/polling (11.2.0.x)

11gR2から初期化パラメーター “_use_adaptive_log_file_sync” デフォルトFALSEが登場しました。

あまり詳細ではないですが、以下に情報があります。

MOS 1541136.1 Waits for "log file sync" with Adaptive Polling vs Post/Wait Choice Enabled

ちなみに11.2.0.3からは、デフォルト TRUEになってました。

パラメーターの名前から分かるとおり、log file sync (つまり、shadow プロセスが、LGWRが行う、REDOログへの書き込み完了通知を待っている) に関して、

- post/wait (セマフォを使ってLGWRがshadowプロセスにREDOログ書き込み完了を通知)- post/polling (shadowプロセスがsleepにより自身でREDOログ書き込み完了を確認)

の2つの方式を動的に変更するといった機能です。

22Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

深まる謎 その2

Shadow process

LGWR process

2789μ秒

588 μ秒 619 μ秒 171 μ秒

656 μ秒commit semctl semtimedop

commit complete

io_submit io_getevents semctl

semtimedop

log file sync

Shadow process

LGWR process

312.308ミリ秒

1068 μ秒

commit

log file sync

semctl nanosleepnanosleepnanosleepcommit

complete

io_submit io_getevents semtimedop

500 μ秒 618 μ秒 615 μ秒 1012 μ秒

833 μ秒 561 μ秒

で、誰が、どんな理由で、お得なんでしょうか?

post/wait

post/polling

23Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

深まる謎 その2 の考察

post/poll

大量のセッションが大量のcommitを同時多発的に

実行した際、post/wait方式であれば、LGWRは全てのcommit要求元にsemctl(2)で通

知する必要がある。

このsemctl(2)による通知が忙しくて、本来の仕事のonline REDOログへフラッシュが怠けがちなっているシステムでは、post/pollingによるsemctl(2)からの解放は有効かもしれない。

LGWRは喜ぶ

従来のpost/waitはLGWRから通知されていたので、可能な限り即時にcommit完了通知を受け

取ることができた。

しかし、post/pollingではnanosleep(2)(このテスト時は466μ秒だったが、実際は動的に決定されると思う)でスリープするので、無駄に寝てしまって、 commitのレイテンシーが悪化する可能性があると思われる。

log file syncは増える可能性もある?

24Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

ん!? (12.1.0.1)

25Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

ん!?なパターンも出てきた (12.1.0.1)

LGWRは新種のLG00(LGWR Worker)へ“左から右に受け流している”SHADOW PROCESS LGWR LG00----------------------------------------------- ---------------------------------------------------- ----------------------------------------------------18:29:18.575401 semtimedop(622604, {{19,…}}, 1, {3, 0}) = -1 EAGAIN18:29:21.577337 semtimedop(622604, {{19,…}}, 1, {3, 0}) = -1 EAGAIN18:29:21.963171 semtimedop(622604, {{21,…}}, 1, {3,0}) = -1 EAGAIN18:29:24.579259 semtimedop(622604, {{19,…}}, 1, {3, 0}) =18:29:24.964188 semtimedop(622604, {{21,…}}, 1, {3,0}) =18:29:25.658472 update !18:29:25.661777 update complete18:29:25.662136 commit !18:29:25.677012 semctl(622604, 19, SETVAL,…) = 018:29:25.677411 semctl(622604, 21, SETVAL, 0x7fff00000001) = 018:29:25.677655 semtimedop(622604, {{19,…}}, 1, {1, 910000000}) =18:29:25.677772 io_submit(139749499707392, 2, {{…}}) = 218:29:25.677838 semtimedop(622604, {{33,…}},…) =18:29:25.678392 io_getevents(139749499707392, 2, 128,…,{0,0}) = 218:29:25.678967 semctl(622604, 33, SETVAL, 0x7fff00000001) = 018:29:25.679130 semctl(622604, 19, SETVAL, 0x7fff00000001) = 018:29:25.679370 semtimedop(622604, {{19,…}},…) =18:29:25.679676 commit complete18:29:27.580963 semtimedop(622604, {{19,…}}, 1, {3, 0}) = -1 EAGAIN

26Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

新種のプロセス LGnn (12.1.0.1)

12cR1から初期化パラメーター “_use_single_log_writer” デフォルトADAPTIVEが登場している。どうやら、Scalable Log Writerとも呼ばれるらしい。

詳細不明ですが、新種のプロセスLGnn(Log Writer Workerプロセス)がデフォルトで2つ起動され、状況により、複数のWorkerプロセスに、I/Oを任せることで、REDOログへの書き込みスループットを向上させようとしていると考えられる。

ちなみに、LGnnのプロセス数は”_max_outstanding_log_writes”で制御されている模様

“_use_single_log_writer”の設定として- TRUE 常にシングル(LGWR)がREDOログへの書き込みを担う。従来の動作- FALSE 常に一旦LGWRが要求を受けて、LGnnがREDOログへ書き込む。- ADAPTIVE きっと、両者を動的に切り替える

27Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

深まる謎 その3

正直、ADAPTIVE状態では、なかなか、Workerプロセスを使うモードに移行してくれなかった。さらに、強制的にWorkerプロセスを使うモード(先ほどのスライドの例)だと、プロセス間通信による遅延が増え、全体的なcommitレスポンスは悪化していた。(そういうパターンもあった)

Scalable Log Writerの力はこんなものではないはずなので、今後、要検証。

Shadow process

LGWR process

log file syncScalable Log Writer

LG00 process

commit semctl semtimedopcommit

complete

semctl semtimedopsemtimedop

semctl semctlio_submit io_getevents

28Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

と言うことで

なじみ深いcommitという動作一つでも、奥は深い。

データベースでは、非常にベーシックなアーキテクチャでも、時代と共に変化していきている。

ただ、その機能やアーキテクチャの変更が、現在のシステムに有効かどうかは、現時点では、ちゃんと見極める必要がある。 (過度に憶病になる必要はないと思いますが)

ただ、流行りのAdaptiveといった説明にならない説明は個人的には嫌いです。

なので、常識の範囲で、中身を見てみると、その機能の気持ちも分かるようになるし、得意、不得意な点も見えてくるので、個人的にはおススメ。

(ただ、本番環境では絶対にやらないでくださいね。)

最後に、データベースのパフォーマンス問題は奥が深いので、一言で解決可能な魔法の薬は存在しません。現象を理解し、深く解析し、データベースやそのプロセスの気持ちになって考えてあげる事が大切です。

29Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

ORA-3113

30Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

#include <stdio.h>#include <stdlib.h>#include <time.h>#include <sys/time.h>#include <unistd.h>

int LOOP = 10;

int main (int argc, char **argv){

struct timeval tv[LOOP];struct timespec req;int i;

req.tv_sec = 0;req.tv_nsec = 1000; // 1us

for (i = 0; i < LOOP; i++) {nanosleep(&req, NULL);gettimeofday(tv + i, NULL);

}

for (i = 0; i < LOOP; i++)printf("%ld:%06ld¥n", (long)tv[i].tv_sec, (long)tv[i].tv_usec);

return 0;}

Appendix: tick_test.c

31Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#include <stdio.h>

#define KEY (1492)

int main(){

int id;union semun {

int val;struct semid_ds *buf;ushort * array;

} argument;

argument.val = 0;id = semget(KEY, 1, 0666 | IPC_CREAT);

if(id < 0){

fprintf(stderr, "Unable to obtain semaphore.¥n");return 0;

}

if( semctl(id, 0, SETVAL, argument) < 0){

fprintf( stderr, "Cannot set semaphore value.¥n");}else{

fprintf(stderr, "Semaphore %d initialized.¥n", KEY);}

}

Appendix: seminit.c

32Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

#include <stdio.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>

#define KEY (1492)

int main(){

int id;int retval;struct timeval tv;

id = semget(KEY, 1, 0666);if(id < 0){

fprintf(stderr, "Program cannot find semaphore, exiting.¥n");return 0;

}

printf("Program about to do a V-operation. ¥n");

gettimeofday(&tv, NULL);printf("%ld:%06ld¥n", (long)tv.tv_sec, (long)tv.tv_usec);retval = semctl(id, 0, SETVAL, 1);

if(retval == 0){

printf("Successful V-operation by program sem_wakeup.¥n");}else{

printf("sem_wait: V-operation did not succeed.¥n");perror("REASON");

}}

Appendix: sem_wakeup.c

33Copyright © 2013 Insight Technology, Inc. All Rights Reserved.

#include <stdio.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#include <stdlib.h>#include <time.h>#include <sys/time.h>#include <unistd.h>

#define KEY (1492)

int main(){

int id;struct sembuf operations[1];int retval;struct timeval tv;struct timespec req;

req.tv_sec = 10;req.tv_nsec = 0;

id = semget(KEY, 1, 0666);if(id < 0){

fprintf(stderr, "Program cannot find semaphore, exiting.¥n");return 0;

}

printf("Program about to do a P-operation. ¥n");printf("Process id is %d¥n", getpid());

operations[0].sem_num = 0;operations[0].sem_op = -1;operations[0].sem_flg = 0;

Appendix: sem_wait.c

gettimeofday(&tv, NULL);printf("%ld:%06ld¥n", (long)tv.tv_sec, (long)tv.tv_usec);

retval = semtimedop(id, operations, 1, &req);

gettimeofday(&tv, NULL);printf("%ld:%06ld¥n", (long)tv.tv_sec, (long)tv.tv_usec);

if(retval == 0){

printf("Successful P-operation by program sem_wait.¥n");printf("Process id is %d¥n", getpid());

}else{

printf("sem_wait: P-operation did not succeed.¥n");}

}