线程同步---信号量(无名)

1. 有名信号量&无名信号量

        在POSIX标准中,信号量分两种,一种是无名信号量,一种是有名信号量。无名信号量只用于线程间的同步,有名信号量只用于进程间通信。信号量是属于POSIX:SEM的,不是属于POSIX:THR的,需要的文件头是<semaphore.h>。两者的共同点都是相当于计数器,用于限制多个进程对有限共享资源的访问

2.  相关函数

1)创建信号量

int sem_init (sem_t* sem, int pshared,unsigned int value);

sem        - 信号量ID,输出。

pshared - 一般取0,表示调用进程的信号量。  非0表示该信号量可以共享内存的方式, 为多个进程所共享(Linux暂不支持)

 value      - 信号量初值。

2)信号量操作函数

int sem_post (sem_t* sem);// 信号量加1
int sem_wait (sem_t* sem);//信号量减1,不够减即阻塞
int sem_trywait (sem_t* sem);// 信号量减1,不够减即返回-1,errno为EAGAIN
int sem_timedwait (sem_t* sem, const struct timespec* abs_timeout);// 信号量减1,不够减即阻塞,直到abs_timeout超时返回-1,errno为ETIMEDOUT
struct timespec {
    time_t tv_sec;  // Seconds
    long   tv_nsec; // Nanoseconds [0 - 999999999]
};
int sem_getvalue(sem_t *sem, int *sval);//把 sem 指向的信号量当前值放置在 sval 指向的整数上

3) 销毁信号量

int sem_destroy (sem_t* sem);

3. 和互斥量的区别与联系: 

     互斥量任何时候都只允许一个线程访问共享资源, 而信号量则允许最多value个线程同时访问共享资源,当value1时,与互斥量等价。

#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>

unsigned int g_cn = 0;

sem_t g_sem;

void* thread_proc (void* arg) {
	unsigned int i;
	for (i = 0; i < 100000; i++) {
		sem_wait (&g_sem);
		g_cn++;
		sem_post (&g_sem);
	}

	return NULL;
}
	
int main (void) {
	size_t i;
	pthread_t tids[2];
	int error;

	sem_init (&g_sem, 0, 1);

	for (i = 0; i < sizeof (tids) / sizeof (tids[0]); i++)
		if ((error = pthread_create (&tids[i], NULL, thread_proc,
			NULL)) != 0) {
			fprintf (stderr, "pthread_create: %s\n", strerror (error));
			return -1;
		}

	for (i = 0; i < sizeof (tids) / sizeof (tids[0]); i++)
		if ((error = pthread_join (tids[i], NULL)) != 0) {
			fprintf (stderr, "pthread_join: %s\n", strerror (error));
			return -1;
		}

	sem_destroy (&g_sem);
	printf ("g_cn = %u\n", g_cn);
	return 0;
}
结果无论运行多少次,一直为20万

4.  模拟实习一个连接池问题,用来对有限资源的访问:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

#define MAX_CONNS 5  // 最大连接数
#define MAX_USERS 50 // 最大用户数

sem_t g_sem;

void* thread_user (void* arg) {
	pthread_t tid = pthread_self ();

	int sval;
	sem_getvalue (&g_sem, &sval);
	printf ("%lu线程:等待数据库连接(还剩%d个空闲连接)...\n", tid, sval);

	sem_wait (&g_sem);
	sem_getvalue (&g_sem, &sval);
	printf ("%lu线程:获得数据库连接(还剩%d个空闲连接)!\n", tid, sval);

	usleep (1000000);

	sem_post (&g_sem);
	sem_getvalue (&g_sem, &sval);
	printf ("%lu线程:释放数据库连接(还剩%d个空闲连接)。\n", tid, sval);

	return NULL;
}

int main (void) {
	size_t i;
	pthread_t tids[MAX_USERS];
	int error;

	sem_init (&g_sem, 0, MAX_CONNS);
    //创建50个线程
	for (i = 0; i < sizeof (tids) / sizeof (tids[0]); i++)
		if ((error = pthread_create (&tids[i], NULL, thread_user,
			NULL)) != 0) {
			fprintf (stderr, "pthread_create: %s\n", strerror (error));
			return -1;
		}
    //回收线程
	for (i = 0; i < sizeof (tids) / sizeof (tids[0]); i++)
		if ((error = pthread_join (tids[i], NULL)) != 0) {
			fprintf (stderr, "pthread_join: %s\n", strerror (error));
			return -1;
		}
    //销毁信号量
	sem_destroy (&g_sem);
	return 0;
}

部分结果图:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值