信号量PV操作在System V和POSIX pthread库间的性能差异

一、请知:

    1. System V信号量每次执行PV操作时,都需要进行用户态和内核态的切换。

    2. POSIX pthread库实现的信号量执行PV操作时,仅当需要时才进行用户态和内核态的切换。具体表述如下:

        2.1 P操作:a) 在用户态“信号量值减一,且值大于等于0”,则无需陷入内核;

                                b) 在用户态“信号量值减一,且值小于0”,则需要陷入内核,并将调用进程插入到该信号量的等待队列,睡眠;

        2.2 V操作:a) 在用户态“信号量值加一,且值大于0”,则无需陷入内核;

                                b) 在用户态“信号量值加一,且值小于等于0”,则需要陷入内核,并唤醒该信号量等待队列上的一个进程;

二、测试代码:

    1. 使用System V信号量进行PV操作:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <assert.h>

#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>

#define SEM_KEY		0x88991110
#define SEM_NUM		2

#define SHM_KEY		0x88991111
#define SHM_SIZE	1024

union semun {
	int              val;    /* Value for SETVAL */
	struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
	unsigned short  *array;  /* Array for GETALL, SETALL */
	struct seminfo  *__buf;  /* Buffer for IPC_INFO
	                            (Linux-specific) */
};

int main(int argc, char *argv[])
{
	int ret = 0;
	int semid = 0, nM = 0;
	union semun arg;

	if (2 != argc) {
		printf("usage: ./pv_sysv num.\n");
		return -1;
	}
	nM = atoi(argv[1]);

	semid = semget(SEM_KEY, 1, IPC_CREAT | IPC_EXCL | 0600);
	if (semid < 0) {
		perror("semget first");

		semid = semget(SEM_KEY, 0, 0);
		if (semid < 0) {
			perror("semget second");
			return -1;
		}
	}

	arg.val = 1;
	ret = semctl(semid, 0, SETVAL, arg);
	if (-1 == ret) {
		perror("semctl");
	}

	struct timeval tmStart = {0}, tmEnd = {0};
	gettimeofday(&tmStart, NULL);

	struct sembuf pops[1] = {{0, -1, SEM_UNDO}};
	struct sembuf vops[1] = {{0, 1, SEM_UNDO}};

	for (uint64_t loop = 0; loop < 1024 * 1024 * nM; loop++) {
		ret = semop(semid, pops, 1);
		if (-1 == ret) {
			perror("P");
		}

		ret = semop(semid, vops, 1);
		if (-1 == ret) {
			perror("V");
		}
	}

	gettimeofday(&tmEnd, NULL);
	uint64_t diff = (tmEnd.tv_sec * 1000 * 1000 + tmEnd.tv_usec) - (tmStart.tv_sec * 1000 * 1000 + tmStart.tv_usec);
	printf("time: %lu us.\n", diff);

	/* 只要调用过shmctl, 当连接数为0时, 该共享内存就会被删除 */
	ret = semctl(semid, 0, IPC_RMID);
	if (ret < 0) {
		perror("shmctl");
	}

	return ret;
}

    2. 使用POSIX pthread线程库信号量进行PV操作:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <assert.h>

#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <semaphore.h>

int main(int argc, char *argv[])
{
	int ret = 0, nM = 0;
	sem_t *semid = NULL;

	if (2 != argc) {
		printf("usage: ./pv_posix num.\n");
		return -1;
	}
	nM = atoi(argv[1]);

	semid = sem_open("lfc.sem", O_CREAT | O_EXCL, 0666, 1);
	if (SEM_FAILED == semid) {
		perror("sem_open first");

		semid = sem_open("lfc.sem", 0);
		if (SEM_FAILED == semid) {
			perror("sem_open second");
			return -1;
		}
	}

	struct timeval tmStart = {0}, tmEnd = {0};
	gettimeofday(&tmStart, NULL);

	for (uint64_t loop = 0; loop < 1024 * 1024 * nM; loop++) {
		ret = sem_wait(semid);
		if (0 != ret) {
			perror("sem_wait");
		}

		ret = sem_post(semid);
		if (0 != ret) {
			perror("sem_post");
		}
	}

	gettimeofday(&tmEnd, NULL);
	uint64_t diff = (tmEnd.tv_sec * 1000 * 1000 + tmEnd.tv_usec) - (tmStart.tv_sec * 1000 * 1000 + tmStart.tv_usec);
	printf("time: %lu us.\n", diff);

	ret = sem_close(semid);
	if (0 != ret) {
		perror("sem_close");
	}

	ret = sem_unlink("lfc.sem");
	if (0 != ret) {
		perror("sem_unlink");
	}

	return ret;
}

三、测试数据:

1. 1M次PV操作:
    1.1 使用pthread信号量。
        root :sem$ time ./pv_posix 1
        time: 48747 us.

        real	0m0.067s
        user	0m0.047s
        sys	0m0.004s
    1.2 使用System V信号量。
        root :sem$ time ./pv_sysv 1
        time: 1013936 us.

        real	0m1.025s
        user	0m0.562s
        sys	0m0.445s
2. 100M次PV操作:
    2.1 使用pthread信号量。
        root :sem$ time ./pv_posix 100
        time: 1774634 us.

        real	0m1.777s
        user	0m1.777s
        sys	0m0.000s
    2.2 使用System V信号量。
        root :sem$ time ./pv_sysv 100
        time: 98256266 us.

        real	1m38.258s
        user	0m57.293s
        sys	0m40.930s

四、结论:

    1. pthread库信号量的PV操作比System V信号量的PV操作具有明显的性能优化,且随着PV操作次数的增加,性能优势更加明显。

    2. 实际项目中,相比于System V信号量,应尽可能多的使用pthread信号量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值