Linux系统编程——线程同步与互斥:无名信号量

信号量概述

信号量广泛用于进程或线程间的同步和互斥,信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。

编程时可根据操作信号量值的结果判断是否对公共资源具有访问的权限,当信号量值大于 0 时,则可以访问,否则将阻塞。PV
原语
是对信号量的操作,一次 P 操作使信号量减1,一次 V 操作使信号量加1。

信号量主要用于进程或线程间的同步和互斥这两种典型情况。

信号量用于互斥:

信号量用于同步:

在 POSIX 标准中,信号量分两种,一种是无名信号量,一种是有名信号量。无名信号量一般用于线程间同步或互斥,而有名信号量一般用于进程间同步或互斥。它们的区别和管道及命名管道的区别类似,无名信号量则直接保存在内存中,而有名信号量要求创建一个文件。

无名信号量基本操作

以下函数所需头文件:

#include <semaphore.h>

注意:编译信号量操作函数时,需要加上参数-lpthread

信号量数据类型为:sem_t

1)初始化信号量

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

功能:

创建一个信号量并初始化它的值。一个无名信号量在被使用前必须先初始化。

参数:

sem:信号量的地址。

pshared:等于 0,信号量在线程间共享(常用);不等于0,信号量在进程间共享。

value:信号量的初始值。

返回值:

成功:0

失败:-1

2)信号量 P 操作(减 1)

int sem_wait(sem_t *sem);

功能:

将信号量的值减 1。操作前,先检查信号量(sem)的值是否为 0,若信号量为 0,此函数会阻塞,直到信号量大于 0 时才进行减 1 操作。

参数:

sem:信号量的地址。

返回值:

成功:0

失败:-1

int sem_trywait(sem_t *sem);

以非阻塞的方式来对信号量进行减 1 操作。若操作前,信号量的值等于 0,则对信号量的操作失败,函数立即返回。

3)信号量 V 操作(加 1)

int sem_post(sem_t *sem);

功能:

将信号量的值加 1 并发出信号唤醒等待线程(sem_wait())。

参数:

sem:信号量的地址。

返回值:

成功:0

失败:-1

4)获取信号量的值

int sem_getvalue(sem_t *sem, int *sval);

功能:

获取 sem 标识的信号量的值,保存在 sval 中。

参数:

sem:信号量地址。

sval:保存信号量值的地址。

返回值:

成功:0

失败:-1

5)销毁信号量

int sem_destroy(sem_t *sem);

功能:

删除 sem 标识的信号量。

参数:

sem:信号量地址。

返回值:

成功:0

失败:-1

无名信号量应用实例

信号量用于互斥实例:

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

sem_t sem; //信号量

void printer(char *str)
{
	sem_wait(&sem);//减一
	while(*str)
	{
		putchar(*str);
		fflush(stdout);
		str++;
		sleep(1);
	}
	printf("\n");

	sem_post(&sem);//加一
}

void *thread_fun1(void *arg)
{
	char *str1 = "hello";
	printer(str1);
}

void *thread_fun2(void *arg)
{
	char *str2 = "world";
	printer(str2);
}

int main(void)
{
	pthread_t tid1, tid2;

	sem_init(&sem, 0, 1); //初始化信号量,初始值为 1

	//创建 2 个线程
	pthread_create(&tid1, NULL, thread_fun1, NULL);
	pthread_create(&tid2, NULL, thread_fun2, NULL);

	//等待线程结束,回收其资源
	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL); 

	sem_destroy(&sem); //销毁信号量

	return 0;
}

运行结果如下:

信号量用于同步实例:

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

sem_t sem_g,sem_p;   //定义两个信号量
char ch = 'a';

void *pthread_g(void *arg)  //此线程改变字符ch的值
{
	while(1)
	{
		sem_wait(&sem_g);
		ch++;
		sleep(1);
		sem_post(&sem_p);
	}
}

void *pthread_p(void *arg)  //此线程打印ch的值
{
	while(1)
	{
		sem_wait(&sem_p);
		printf("%c",ch);
		fflush(stdout);
		sem_post(&sem_g);
	}
}

int main(int argc, char *argv[])
{
	pthread_t tid1,tid2;
	sem_init(&sem_g, 0, 0);   //初始化信号量
	sem_init(&sem_p, 0, 1);

	pthread_create(&tid1, NULL, pthread_g, NULL);
	pthread_create(&tid2, NULL, pthread_p, NULL);

	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL);

	return 0;
}

运行结果如下:

本教程示例代码下载请点此处。

时间: 2024-10-07 03:43:56

Linux系统编程——线程同步与互斥:无名信号量的相关文章

Linux系统编程——线程同步与互斥:读写锁

当有一个线程已经持有互斥锁时,互斥锁将所有试图进入临界区的线程都阻塞住.但是考虑一种情形,当前持有互斥锁的线程只是要读访问共享资源,而同时有其它几个线程也想读取这个共享资源,但是由于互斥锁的排它性,所有其它线程都无法获取锁,也就无法读访问共享资源了,但是实际上多个线程同时读访问共享资源并不会导致问题. 在对数据的读写操作中,更多的是读操作,写操作较少,例如对数据库数据的读写应用.为了满足当前能够允许多个读出,但只允许一个写入的需求,线程提供了读写锁来实现.... www.worlduc.com/

Linux系统编程——线程同步与互斥:互斥锁

为什么需要互斥锁? 在多任务操作系统中,同时运行的多个任务可能都需要使用同一种资源.这个过程有点类似于,公司部门里,我在使用着打印机打印东西的同时(还没有打印完),别人刚好也在此刻使用打印机打印东西,如果不做任何处理的话,打印出来的东西肯定是错乱的. 下面我们用程序模拟一下这个过程,线程一需要打印" hello ",线程二需要打印" world ",不加任何处理的话,打印出来的内容会错乱: #include <stdio.h> #include <

linux系统编程--线程同步

同步概念 所谓同步,即同时起步,协调一致.不同的对象,对“同步”的理解方式略有不同. 如,设备同步,是指在两个设备之间规定一个共同的时间参考: 数据库同步,是指让两个或多个数据库内容保持一致,或者按需要部分保持一致: 文件同步,是指让两个或多个文件夹里的文件保持一致.等等 而,编程中.通信中所说的同步与生活中大家印象中的同步概念略有差异.“同”字应是指协同.协助.互相配合.主旨在协同步调,按预定的先后次序运行. 线程同步 同步即协同步调,按预定的先后次序运行. 线程同步,指一个线程发出某一功能调

Linux环境编程之同步(四):Posix信号量

信号量是一种用于提供不同进程间或一个给定进程的不同线程间同步手段的原语.有三种类型:Posix有名信号量,使用Posix IPC名字标识:Posix基于内存的信号量,存放在共享内存区中:System V信号量,在内核中维护.这三种信号量都可用于进程间或线程间的同步. 图1 由两个进程使用的一个二值信号量 图2 由两个进程使用的一个Posix有名二值信号量 图3 由一个进程内的两个线程共享的基于内存的信号量 一个进程可以在某个信号量上执行的三种操作: 1.创建一个信号量,这要求调用者指定初始值,对

linux网络编程-----&gt;线程同步一

开发使用多线程过程中, 不可避免的会出现多个线程同时操作同一块共享资源, 当操作全部为读时, 不会出现未知结果, 一旦当某个线程操作中有写操作时, 就会出现数据不同步的事件. 而出现数据混乱的原因: 资源共享(独享资源则不会) 调试随机(对数据的访问会出现竞争) 线程间缺少必要的同步机制 以上三点, 前两点不能被改变. 欲提高效率, 传递数据, 资源必须共享. 只要资源共享, 就一定会出现线程间资源竞争, 只要存在竞争关系, 数据就会出现混乱. 所以只能从第三点着手, 使多个线程在访问共享资源的

linux网络编程-----&gt;线程同步--&gt;信号量

开发使用多线程过程中, 不可避免的会出现多个线程同时操作同一块共享资源, 当操作全部为读时, 不会出现未知结果, 一旦当某个线程操作中有写操作时, 就会出现数据不同步的事件. 而出现数据混乱的原因: 资源共享(独享资源则不会) 调试随机(对数据的访问会出现竞争) 线程间缺少必要的同步机制 以上三点, 前两点不能被改变. 欲提高效率, 传递数据, 资源必须共享. 只要资源共享, 就一定会出现线程间资源竞争, 只要存在竞争关系, 数据就会出现混乱. 所以只能从第三点着手, 使多个线程在访问共享资源的

linux网络编程-----&gt;线程同步--&gt;条件变量

开发使用多线程过程中, 不可避免的会出现多个线程同时操作同一块共享资源, 当操作全部为读时, 不会出现未知结果, 一旦当某个线程操作中有写操作时, 就会出现数据不同步的事件. 而出现数据混乱的原因: 资源共享(独享资源则不会) 调试随机(对数据的访问会出现竞争) 线程间缺少必要的同步机制 以上三点, 前两点不能被改变. 欲提高效率, 传递数据, 资源必须共享. 只要资源共享, 就一定会出现线程间资源竞争, 只要存在竞争关系, 数据就会出现混乱. 所以只能从第三点着手, 使多个线程在访问共享资源的

Linux系统编程——线程池

线程池基本原理 在传统服务器结构中,常是有一个总的监听线程监听有没有新的用户连接服务器,每当有一个新的用户进入,服务器就开启一个新的线程用户处理这 个用户的数据包.这个线程只服务于这个用户,当用户与服务器端关闭连接以后,服务器端销毁这个线程.(关于并发服务器更多详情,请看<并发服务器>). 然而频繁地开辟与销毁线程极大地占用了系统的资源,而且在大量用户的情况下,系统为了开辟和销毁线程将浪费大量的时间和资源.线程池提供了一个解决外部大量用户与服务器有限资源的矛盾. 线程池和传统的一个用户对应一个

Linux系统编程——线程私有数据

在多线程程序中,经常要用全局变量来实现多个函数间的数据共享.由于数据空间是共享的,因此全局变量也为所有线程共有. 测试代码如下: #include <stdio.h> #include <pthread.h> #include <unistd.h> #include <stdlib.h> int key = 100; //全局变量 void *helloworld_one(void *arg) { printf("the message is %s