1.信号量
信号量是一个计数器, 与其它进程间通信方式不大相同, 它主要用于控制多个进程间或一个进程内的多个线程间对共享资源的访问, 相当于内存中的标志,进程可以根据它判定是否能够访问某些共享资源,主要作为进程间以及同一个进程内不同线程之间的同步手段,有很多博文把他归纳为IPC七大法,其实信号量不属于进程间通信,只能用户进程/线程间同步
信号量表示资源的数量,控制信号量的方式有两种原子操作:
• sem_wait函数调用将会阻塞当前进程(或线程),直到信号量的值大于0。当进程执行sem_wait时,如果信号量的值为0(没有可用资源),进程将会被阻塞,直到有其他进程(或线程)调用sem_post增加了信号量的值。
• sem_post函数调用会释放一个信号量,将信号量的值加1。当某进程(或线程)执行sem_post时,如果有其他进程(或线程)正在等待该信号量,其中一个被阻塞的进程(或线程)就会被唤醒,并且被允许访问共享资源。
sem_wait和sem_post可以视为互斥锁的机制,只允许一个进程通过sem_wait访问临界区,而其他进程将会被阻塞。 总而言之,sem_wait会阻塞当前进程(或线程),直到信号量的值大于0。而sem_post会释放一个信号量,唤醒一个被阻塞的进程或线程
#include <stdio.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
int main(void)
{
sem_t *sem_id = NULL;
int pid;
sem_id = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
sem_init(sem_id, 1, 1); // 初始化一个信号量
pid = fork();
if (pid > 0)
{
while (1)
{
sem_wait(sem_id); // 等待信号量,阻塞当前线程直到信号量sem的值大于0
printf("pid>0,是父进程\n");
sleep(2);
}
}
else if (pid == 0)
{
while (1)
{
printf("pid==0,是子进程\n");
sem_post(sem_id); // 释放信号量,增加信号量的值,调用这个函数会导致其中一个线程不阻塞,如果补调用sem_post.会导致父进程被阻塞,只有子进程在输出
}
}
else
{
printf("创建子进程失败\n");
}
return 0;
}
2.lockf
lockf函数,它是一个文件锁定函数,用于在文件的某个部分上设置锁。
lockf(1, 1, 0) 用于申请锁,将标准输出锁定,避免多个进程同时写入输出时出现混乱。lockf(1, 0, 0) 用于释放锁,允许其他进程再次申请锁
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int pid, i;
if ((pid = fork()) < 0)
{
printf("child fails to create\n");
return 0;
}
else if (pid == 0)
{
lockf(1, 1, 0);
for (i = 0; i < 100; i++)
printf("This is child (pid = %d)process:b\n", getpid());
lockf(1, 0, 0);
}
else
{
lockf(1, 1, 0);
for (i = 0; i < 200; i++)
printf("Parent process:a,pid is %d\n", getpid());
lockf(1, 0, 0);
}
return 0;
}
因为多进程之间的输出顺序是不固定的,如果不加lockf,上述结果,就是在出现输出父进程的时候穿插输出子进程,而加入lockf之后,不会出现抢占,lockf只能控制进程间的互斥,运行结果如下