linux c 网络编程与信号量,linux网络编程之posix信号量与互斥锁

继上次学习了posix线程之后,这次来讨论一下posix信号量与互斥锁相关的知识:

a80550e5567473ee3c9202a5ede06ab0.png

1dcb1085235d032b13f344519be81b1c.png

跟posix消息队列,共享内存的打开,关闭,删除操作一样,不过,上面的函数是对有名信号量进行操作,通过man帮助可以得知:

4d2c7bd8b15960a8768efec811c153d2.png

有名信号量相对的那就是无名信号量,对于它相关的函数如下:

d633d510e683f4b5295fa967bcd2a8fd.png

同样可以查看man帮助:

759d876bfcac6f45b43a5df73ab8f212.png

【思考】:是不是无名信号量就无法用于不同进程间的多个线程间进行通信呢?实际上不是这样的:

5d2e2da00d9727b56078b1c5bf142ad3.png

而对于信号量的P、V操作,可以用以下两个函数,既能用于有名,也能用于无名信号量:

67406bdee881b2aea711e165c27e4e56.png

00ed2a215f4bc6f014b3807f94516df6.png

初始化互斥锁:

ac072d4cecb1cd7f937ce574eb9c3102.png

锁定操作:

26b31e54e995031f5a587a3b5dace877.png

解锁操作:

e95f2acc182dc2381e9bf658bf9ea9f4.png

锁屏互斥锁:

02e8180d36f36580e532a56eeb34cd1e.png

【说明】:以上四个函数也是应用于无名的,也可以用于不同进程的不同线程间进行通信。

接下来就用信号量与互斥锁来解决生产者消费者的问题:

66d40fe9dcb531c13eb12750e56a4046.png

下面利用posix信号量与互斥锁来模拟生产者消费者问题:

由于生产者与消费者可以有多个,所以这两个的个数可以定义成一个宏,便于随意更改:

f6add18b87f7feb4dddbf67129402ed3.png

d98ae729f6970780fd0067146d6ff64f.png

接下来要定义一些信号量和互斥锁变量:

27aa24615ad9e405aff131fae32c5418.png

348606ba5f0023b5c2a1745359fc17da.png

以上是一些全局数据的初始化,接下来则开始真正代码的编写,首先得初始化信号量和互斥锁:

81a57e3edd372a318ca13255425f3373.png

接下来创建若干个线程:

b71d1e21720b10d490a2a60442dc2819.png

4cd965578d7adcf72d5ab681a96982a2.png

接下来来编写生产者与消费者的入口函数的实现:

705c730d61363ef6edd135cdfea81a16.png

先来实现生产产品的代码:

在正式生产之前,先打印出仓库当前的状态,也就是缓冲区里:

401601ccd4fa6b8d7f1c5e0016dcbfc9.png

同样的,在消费之前,也打印一下当前仓库消费的状态:

6a453974a28d66e0f709b9e891db870d.png

打印状态之后,则开始生产产品:

cb6e24b2fcec3376928ce94c2b2d3a29.png

697d870e1a411649a1571286cac14dd7.png

同样的消费者也类似:

77a52d531842843586d8d9e203b4121a.png

至此代码功能已经编写完成,下面则通过调整生产者与消费者的个数,再配合睡眠来查看一下运行结果:

情况一:生产产品比较快,消费产品比较慢,所以经常有产品满的情况,也就是生产者会出现等待。

aa627d5bf57776da8eda633c2434846a.png

39708321d7eadca6726a15db71011ab2.png

d218047bd65f99c9b0b3ce0f9ba44151.png

编译运行:

8b123bd21d038fa96855ea044067ddc5.gif

从结果中来以发现:

80f3c73e84692ef0b09932e800b35609.png

情况二:生产产品比较慢,但是消费得比较快,所以经常出现产品为空的情况,也就是消费者会不断出现等待。

4fdd4fee20f797e26c0317887930b7f5.png

33fe541db912d7c30ca09739b7ca370e.png

bc4b7f7b3c9dddeb56d25e31fc97173c.png

下面再来看下这种情况的效果:

243256da623ce5187e269ce3feb936a2.gif

从中可以发现:

1c33d9df8eb29e0219aa9ded9f5aef91.png

以上就是实验的结果,下面再了解两个相关的线程锁。

cf0c82af32b38e32c0bd0a8198129d1d.png【仅作了解】

36c8c7b9dea62247602e352714b1e0ee.png

2a4662a9ab2e5a3c376f50d1ece99e6f.png

6f08d9f6d2e4c0c65cc9f20b356465bf.png

fb3b5975c37101eee87c5eecae186815.png

也就是说如果对某个临界区施加了共享锁,意味着还可以对其施加共享锁;而如果对临界区施加了共享锁或排它锁,则不允许其它线程对它施加排它锁。

最后再附上实验的代码:

#include #include#include#include#include#include#include#include

#define ERR_EXIT(m)

do{

perror(m);

exit(EXIT_FAILURE);

}while(0)#define CONSUMERS_COUNT 1

#define PRODUCERS_COUNT 1

#define BUFFSIZE 10

intg_buffer[BUFFSIZE];

unsignedshort in = 0;

unsignedshort out = 0;

unsignedshort produce_id = 0;

unsignedshort consume_id = 0;

sem_t g_sem_full;

sem_t g_sem_empty;

pthread_mutex_t g_mutex;

pthread_t g_thread[CONSUMERS_COUNT+PRODUCERS_COUNT];void* consume(void *arg)

{int num = (int)arg;inti;while (1)

{

printf("%d wait buffer not empty", num);

sem_wait(&g_sem_empty);

pthread_mutex_lock(&g_mutex);//消费产品

for (i=0; i

{

printf("%02d", i);if (g_buffer[i] == -1)

printf("%s", "null");elseprintf("%d", g_buffer[i]);if (i == out)

printf("

printf("");

}

consume_id= g_buffer[out];

printf("%d begin consume product %d", num, consume_id);

g_buffer[out] = -1;out = (out + 1) %BUFFSIZE;

printf("%d end consume product %d", num, consume_id);

pthread_mutex_unlock(&g_mutex);

sem_post(&g_sem_full);

sleep(1);

}returnNULL;

}void* produce(void *arg)

{int num = (int)arg;inti;while (1)

{

printf("%d wait buffer not full", num);

sem_wait(&g_sem_full);

pthread_mutex_lock(&g_mutex);//生产产品的代码

for (i=0; i

{

printf("%02d", i);if (g_buffer[i] == -1)

printf("%s", "null");elseprintf("%d", g_buffer[i]);if (i == in)

printf("

printf("");

}

printf("%d begin produce product %d", num, produce_id);

g_buffer[in] =produce_id;in = (in + 1) %BUFFSIZE;

printf("%d end produce product %d", num, produce_id++);

pthread_mutex_unlock(&g_mutex);

sem_post(&g_sem_empty);

sleep(5);

}returnNULL;

}int main(void)

{inti;for (i=0; i

g_buffer[i]= -1;

sem_init(&g_sem_full, 0, BUFFSIZE);

sem_init(&g_sem_empty, 0, 0);

pthread_mutex_init(&g_mutex, NULL);for (i=0; i

pthread_create(&g_thread[i], NULL, consume, (void*)i);for (i=0; i

pthread_create(&g_thread[CONSUMERS_COUNT+i], NULL, produce, (void*)i);for (i=0; i

pthread_join(g_thread[i], NULL);

sem_destroy(&g_sem_full);

sem_destroy(&g_sem_empty);

pthread_mutex_destroy(&g_mutex);return 0;

}

好了,先学到这~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值