学习记录第二十九天

信号量————来描述可使用资源的个数

信号量(Semaphore)是一种用于控制多个进程或线程对共享资源访问的同步机制。在C语言中,通常我们会使用POSIX线程(pthread)库来实现信号量的操作

信号量有两个主要操作:P(等待)和V(释放)

初始化信号量

静态初始化

sem_t sem;  
sem = SEM_INITIALIZER(1); // 初始值为1

动态初始化 

sem_t sem;  
sem_init(&sem, 0, 1); // 第二个参数为0表示信号量是进程内的,初始值为1

 操作信号量

等待(P操作)

sem_wait函数将阻塞调用线程,直到信号量的值大于0。调用成功后,信号量的值减1。

 sem_wait(&sem);

信号(V操作)

sem_post函数将信号量的值增加1,并唤醒正在等待该信号量的一个线程(如果有的话)。

sem_post(&sem);

 

尝试等待(非阻塞)

sem_trywait函数尝试对信号量执行P操作,但如果信号量的值为0,则不会阻塞调用线程,而是立即返回一个错误。 

if (sem_trywait(&sem) == 0)

{

// 成功获取信号量

}

else

{

// 信号量值为0,处理错误

}

 销毁信号量 

sem_destroy(&sem);

sem_t sem_w;
sem_t sem_r;

char buf[100] = {0};
void* doSth1(void* arg)
{
    while(1)
    {
        sem_wait(&sem_w);
        printf(">");
        fgets(buf,sizeof(buf),stdin);
        sem_post(&sem_r);
    }
}

void* doSth2(void* arg)
{
    while(1)
    {
        sem_wait(&sem_r);
        printf("buf = %s",buf);
        sem_post(&sem_w);
    }
}

int main(int argc, char *argv[])
{
    sem_init(&sem_w,0,1);
    sem_init(&sem_r,0,0);
    pthread_t tid[2];

    int ret = pthread_create(&tid[0],NULL,doSth1,NULL);
        if(ret != 0)
        handle_error_en(ret,"pthread_create fail");
    
    ret = pthread_create(&tid[1],NULL,doSth2,NULL);
        if(ret != 0)
        handle_error_en(ret,"pthread_create fail");

    pthread_join(tid[0],NULL);
    pthread_join(tid[1],NULL);
    sem_destroy(&sem_w);
    sem_destroy(&sem_r);

    return 0;
}

进程间的通信 

同一主机:古老的通信方式;

                                 管道:通过操作系统提供的内存缓冲区,在内核中实现的通信机制。

                                        有名管道:有名管道则可以跨越无亲缘关系的进程。

                                        无名管道:无名管道只能用于具有亲缘关系的进程间通信

                                  信号:操作系统通过信号来通知进程系统中发生了某种预先规定好的事件。

                      IPC对象通信:

                                   消息队列:在进程之间传递数据的通信机制,通过消息队列标识符进行                                                              通信。

                                   共享内存 :允许多个进程访问同一块物理内存区域。最快的IPC形式之一一                                                        因为进程可以直接访问共享内存中的数据,无需进行数据的复                                                          制。但需要开发者自行负责同步和互斥,以防止数据竞争和一                                                           致性问题。

                                   信号量级:一个计数器,用于控制多个进程对共享资源的访问。

不同主机:socket通信:网络通信 

无名管道

pipe() 函数

通过pipe()函数创建了管道,你就可以在进程间通过它来传递数据了。通常,一个进程(如父进程)会写入管道,而另一个进程(如子进程)会从管道中读取数据。

#include <unistd.h>

int pipe(int filedes[2]);

  • 参数filedes是一个整型数组,用于存储管道的两个文件描述符。filedes[0]用于读管道,filedes[1]用于写管道。
  • 返回值:成功时返回0;失败时返回-1,并设置errno以指示错误。

 pipefd函数

它创建一个管道,并返回两个文件描述符,一个用于读(pipefd[0]),另一个用于写(pipefd[1])

管道的读写规则:
1.读端存在,写管道
  管道空:可以写数据
  管道满:会造成-->写阻塞 
  
2.读端不存在,写管道
  系统会给进程发一个信号SIGPIPE(管道破裂)

3.写端存在,读管道
  管道空,读不到数据,
  这时会造成读操作阻塞

4.写端不存在,读管道 
  如果管道中有数据,则读取这些数据!
  如果没有数据,读操作不阻塞,立即返回!

 管道的特点:

  1. 半双工通信
    管道是半双工的,意味着在同一时间内数据只能沿一个方向流动。如果需要双向通信,必须创建两个管道,一个用于一个方向的通信,另一个用于相反方向的通信。

  2. 基于文件描述符
    管道是通过文件描述符来访问的。在创建管道时,系统返回两个文件描述符:一个用于读(read),另一个用于写(write)。这些文件描述符在文件系统中没有对应的文件,它们是内核中的特殊文件。

  3. 数据流动性
    数据一旦被写入管道,就会被读取端立即读取(如果有进程在读取)。一旦数据被读取,它就会从管道中消失,无法再次被读取(除非有数据复制机制)。这意味着管道不支持像文件那样的随机访问。

  4. 有限容量
    管道有一个有限的容量(65536字节),这取决于系统的实现。如果管道满了,写入操作将会阻塞,直到有足够的空间为止(除非是非阻塞模式或使用了特定的系统调用选项)。类似地,如果管道为空,并且没有进程在写入,读取操作也可能会阻塞。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值