#author("2018-03-25T09:07:49+00:00","default:haikikyou","haikikyou")
[[Unix-Linux]]


* Read-Write Lock [#fcad82f1]

&label(study){実験}; ''共有メモリ上でのpthread_rwlock''

shared設定するとプロセス間でmutexを利用することができる。Read-Writeロックについて、Linuxではwriteロック待ちのスレッドがいても、readロックが取得できてしまう?現象があるようだ。これについては、非標準の&code(){PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP};を指定すると回避できる(実際に利用する場合には、各プラットフォームで要検証)

#geshi(c,number){{{
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <sys/shm.h>
#include <string.h>

#define CHILD_NUM 	4
#define IPCProtection	(0600)
#define MAX_SHMEM	3
#define BUFSIZE		128

/*
 * Shared memory
 */
typedef struct Shm
{
	int shmid;
	void *memaddr;
} Shm;

static Shm shmem[MAX_SHMEM];
static int shmem_idx = 0;

/* pointer on shared memory */
static pthread_rwlock_t *rwlock;
static char *shared_data;
volatile int* shutdown_flag;

/* child processes */
static pid_t child_procs[CHILD_NUM];

/* my process id */
static int myid;

static pid_t spawn(void);
static void do_it(void);
static void wait_children(void);
static void kill_all_children(int sig);
static void* shmem_create(int idx, size_t size);
static void shmem_detach(void);
static void shmem_destroy(void);

static pid_t spawn(void)
{
	pid_t pid;

	pid = fork();

	if (pid < 0) {
		perror("failed to fork");
		exit(1);
	} else if (pid == 0) {
		myid = getpid();
		do_it();
	}

	return pid;
}

static void do_it(void)
{
	char buf[BUFSIZE];
	for (;;)
	{
		pthread_rwlock_rdlock(rwlock);
		{
			//pthread_rwlock_rdlock(rwlock); /* DeadLock!! */
			memcpy(buf, shared_data, BUFSIZE);
			printf("child[%d]: %ld: %s\n", myid, time(NULL), buf);
			fflush(stdout);
			memset(buf, 0, sizeof(buf));
		}
		pthread_rwlock_unlock(rwlock);

		if (*shutdown_flag == 1)
			break;

		sleep(1);
	}

	shmem_detach();
	exit(0);
}

static void kill_all_children(int sig)
{
	int i;
	for (i = 0; i < CHILD_NUM; ++i)
	{
		if (child_procs[i] != 0)
			kill(child_procs[i], sig);
	}
}

static void wait_children(void)
{
	pid_t pid;
	int status;

	do {
		pid = waitpid(-1, &status, 0);
	} while (pid > 0 || errno == EINTR);

}

static void* shmem_create(int idx, size_t size)
{
	if (MAX_SHMEM <= idx)
		return NULL;

	shmem[idx].shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | IPC_EXCL | IPCProtection);
	if (shmem[idx].shmid < 0) {
		perror("main : shmget ");
		return NULL;
	}

	shmem[idx].memaddr = shmat(shmem[idx].shmid, NULL, 0);
	if (shmem[idx].memaddr == (void *) -1) {
		perror("main : shmat ");
		shmctl(shmem[idx].shmid, IPC_RMID, NULL);
		return NULL;
	}

	return shmem[idx].memaddr;
}

static void shmem_detach(void)
{
	int i;
	for (i = 0; i < MAX_SHMEM; ++i)
	{
		if (shmdt((void *) shmem[i].memaddr) < 0)
		{
			perror("main : shmdt ");
		}
	}
}

static void shmem_destroy(void)
{
	int i;
	for (i = 0; i < shmem_idx; ++i)
	{
		if (shmdt((void *) shmem[i].memaddr) < 0)
		{
			perror("main : shmdt ");
		}

		if (shmctl(shmem[i].shmid, IPC_RMID, NULL) < 0)
		{
			perror("main : shmctl ");
		}
	}
}

int main(int argc, char *argv[])
{
	int i;

	pthread_rwlockattr_t attrrwlock;
	pthread_rwlockattr_init(&attrrwlock);
	/* This setting is needed on Linux. */
#ifdef	__USE_UNIX98
	pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
#endif
	pthread_rwlockattr_setpshared(&attrrwlock, PTHREAD_PROCESS_SHARED);

	rwlock = shmem_create(shmem_idx++, sizeof(pthread_rwlock_t));
	if (rwlock == NULL) {
		perror("main : shmat ");
		exit(EXIT_FAILURE);
	}

	if (pthread_rwlock_init(rwlock, &attrrwlock))
	{
		perror("main: pthread_rwlock_init ");
		exit(EXIT_FAILURE);
	}

	pthread_rwlockattr_destroy(&attrrwlock);

	shared_data = shmem_create(shmem_idx++, BUFSIZE);
	if (shared_data == NULL) {
		perror("main: shmat ");
		exit(EXIT_FAILURE);
	}

	shutdown_flag = shmem_create(shmem_idx++, sizeof(int));
	if (shutdown_flag == NULL) {
		perror("main: shmat ");
		exit(EXIT_FAILURE);
	}
	*shutdown_flag = 0;

	for (i = 0; i < CHILD_NUM; ++i)
		child_procs[i] = spawn();

	int retries = 5;
	char* messages[] = {
		"hello", "world", "foo", "bar", "oops!"
	};

	setbuf(stdout, NULL);

	while (retries-- > 0)
	{
		char *m = messages[retries % 5];
		pthread_rwlock_wrlock(rwlock);
		{
			strncpy(shared_data, m, strlen(m));
			sleep(2);
		}
		pthread_rwlock_unlock(rwlock);

		sleep(1);
	}

	*shutdown_flag = 1;

	kill_all_children(SIGTERM);
	wait_children();

	shmem_destroy();

	puts("done");
	exit(0);
}
}}}

&label(warn){参考};
- [[GNU/Linux でのスレッドプログラミング>http://www.tsoftware.jp/nptl/]] - &size(11){&color(gray){on http://www.tsoftware.jp/nptl/};};
- [[Linux上でのマルチスレッドプログラミングの注意点>https://www.soum.co.jp/misc/individual/multi-thread/]] - &size(11){&color(gray){on https://www.soum.co.jp/misc/individual/multi-thread/};};
- [[Man page of PTHREAD_RWLOCKATTR_SETKIND_NP>https://linuxjm.osdn.jp/html/LDP_man-pages/man3/pthread_rwlockattr_setkind_np.3.html]] - &size(11){&color(gray){on https://linuxjm.osdn.jp/html/LDP_man-pages/man3/pthread_rwlockattr_setkind_np.3.html};};
- [[pthread_rwlockattr_setpshared() - プロセス共用読み取りまたは書き込みロック属性の設定>https://www.ibm.com/support/knowledgecenter/ja/SSLTBW_2.2.0/com.ibm.zos.v2r2.bpxbd00/rp0ras.htm]] - &size(11){&color(gray){on https://www.ibm.com/support/knowledgecenter/ja/SSLTBW_2.2.0/com.ibm.zos.v2r2.bpxbd00/rp0ras.htm};};
- [[マルチスレッドのプログラミング pthread_rwlockattr_setpshared(3T)>https://docs.oracle.com/cd/E19455-01/806-2732/sync-58/index.html]] - &size(11){&color(gray){on https://docs.oracle.com/cd/E19455-01/806-2732/sync-58/index.html};};
- [[FreeBSD Manual Pages (pthread_rwlockattr_setpshared)>https://www.freebsd.org/cgi/man.cgi?query=pthread_rwlockattr_setpshared&sektion=3&manpath=FreeBSD+11.1-stable]] - &size(11){&color(gray){on https://www.freebsd.org/cgi/man.cgi?query=pthread_rwlockattr_setpshared&sektion=3&manpath=FreeBSD+11.1-stable};};
- [[pthread_rwlockattr_setpshared(3) - Linux man page>https://linux.die.net/man/3/pthread_rwlockattr_setpshared]] - &size(11){&color(gray){on https://linux.die.net/man/3/pthread_rwlockattr_setpshared};};
* シグナル [#d3efd0cb]

スレッドごとにシグナルマスクを持つ。シグナルはプロセスに送られ、複数のスレッドがいる場合は、実行中の任意のスレッドに送られる。どのスレッドが捕捉するかはシグナルマスクによる。特定のスレッドにシグナルを処理して欲しい場合は、他のスレッドでシグナルをブロックすればよい。

マルチスレッドプログラムでシグナルをマスクする場合、&code(){pthread_sigmask}; 関数を使用する。マルチスレッドプログラムで、&code(){sigprocmask};関数を使用した場合の動作は未定義となっている。

#geshi(c,number){{{

}}}

* 参考リンク [#cb5aa206]

- [[Linuxとpthreadsによる マルチスレッドプログラミング入門 (プログラミング基礎講座)>http://www.amazon.co.jp/exec/obidos/ASIN/4798053724/haikikyou-22/ref=nosim]] - &size(11){&color(gray){on http://www.amazon.co.jp/};};
- [[Pthreadsプログラミング>http://www.amazon.co.jp/exec/obidos/ASIN/4900900664/haikikyou-22/ref=nosim/]] - &size(11){&color(gray){on http://www.amazon.co.jp/};};
- [[Man page of PTHREADS>https://linuxjm.osdn.jp/html/LDP_man-pages/man7/pthreads.7.html]] - &size(11){&color(gray){on https://linuxjm.osdn.jp/html/LDP_man-pages/man7/pthreads.7.html};};
- [[Multithreaded Programming (POSIX pthreads Tutorial)>https://randu.org/tutorials/threads/]] - &size(11){&color(gray){on https://randu.org/tutorials/threads/};};
- [[POSIX thread (pthread) libraries>https://www.cs.cmu.edu/afs/cs/academic/class/15492-f07/www/pthreads.html]] - &size(11){&color(gray){on https://www.cs.cmu.edu/afs/cs/academic/class/15492-f07/www/pthreads.html};};
- [[マルチスレッドのプログラミング>https://docs.oracle.com/cd/E19455-01/806-2732/index.html]] - &size(11){&color(gray){on https://docs.oracle.com/cd/E19455-01/806-2732/index.html};};
- [[POSIXスレッド(2)>http://www.hpcs.cs.tsukuba.ac.jp/~tatebe/lecture/h22/syspro/l7-thread.pdf]] - &size(11){&color(gray){on http://www.hpcs.cs.tsukuba.ac.jp/~tatebe/lecture/h22/syspro/l7-thread.pdf};};
- [[マルチスレッド・プログラミング(1)/ Multithread programming (1)>http://www.cs.tsukuba.ac.jp/~yas/cs/csys-2013/2013-10-08/]] - &size(11){&color(gray){on http://www.cs.tsukuba.ac.jp/~yas/cs/csys-2013/2013-10-08/};};
- [[CITO Research 2010 年 7 月 マルチコアのジレンマ ホワイト ペーパー>https://www.agtech.co.jp/products/pervasive/psql/v11/pdf/WP_The_Multi-core_Dilemma.pdf]] - &size(11){&color(gray){on https://www.agtech.co.jp/products/pervasive/psql/v11/pdf/WP_The_Multi-core_Dilemma.pdf};};
- [[GNU/Linux でのスレッドプログラミング>http://www.tsoftware.jp/nptl/]]- &size(11){&color(gray){on http://www.tsoftware.jp/nptl/};};
- Pthreadのスタック
-- [[スタックオーバーフローのハンドリング (Stack Overflow Handling)>http://www.nminoru.jp/~nminoru/programming/stackoverflow_handling.html]] - &size(11){&color(gray){on http://www.nminoru.jp/~nminoru/programming/stackoverflow_handling.html};};
- 非同期シグナルセーフな関数
-- [[2.4.3 Signal Actions(非同期シグナルセーフな関数)>http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03]] - &size(11){&color(gray){on http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html};};
-- [[Linux - Man Page of Signal >https://linuxjm.osdn.jp/html/LDP_man-pages/man7/signal.7.html]] - &size(11){&color(gray){on https://linuxjm.osdn.jp/html/LDP_man-pages/man7/signal.7.html};};
-- [[fork(The Open Group Base Specifications Issue 6)>http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html]] - &size(11){&color(gray){on http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html};};
-- [[JPCERT/CC - SIG30-C. シグナルハンドラ内では非同期安全な関数のみを呼び出す>https://www.jpcert.or.jp/sc-rules/c-sig30-c.html]] - &size(11){&color(gray){on https://www.jpcert.or.jp/sc-rules/c-sig30-c.html};};



トップ   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
目次
ダブルクリックで閉じるTOP | 閉じる
GO TO TOP