文件IO(十六)(下)

简介: 文件IO(十六)(下)

练习


共有三个线程,123线程分别打印A B C,循环打印后,最终输出的结果是BCA BCA BCA


#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <semaphore.h>
//定义无名信号灯
sem_t sem1;
sem_t sem2;
sem_t sem3;
void* myfun1(void *arg)
{
    while(1)
    {
        sem_wait(&sem1);
        printf("B\n");
        sem_post(&sem2);
    }
}
void* myfun2(void *arg)
{
    while(1)
    {
        sem_wait(&sem2);
        printf("C\n");
        sem_post(&sem3);
    }
}
int main(int argc, char const *argv[])
{
    sem_init(&sem1,0,1);
    sem_init(&sem2,0,0);
    sem_init(&sem3,0,0);
    pthread_t tid = 0;
    pthread_t tid1 = 0;
    if(0 != pthread_create(&tid,NULL,myfun1,NULL))
    {
        perror("pthread_create");
    }
    if(0 != pthread_create(&tid,NULL,myfun2,NULL))
    {
        perror("pthread_create1");
    }
    while(1)
    {
        sleep(1);
        sem_wait(&sem3);
        printf("A\n");
        sem_post(&sem1);
    }
    return 0;
}


1.4 线程间的互斥


互斥:与同步机制不同的点在于无需顺序执行,必须保证同一时间内只允许有一个线程去访问临界资源。实质上是保证同一临界区只允许同一时间运行一个临界资源。

临界资源:多线程共享的易改变的资源

临界区:修改临界资源的代码

注意:同步一定会互斥,但是互斥不一定同步

互斥机制:互斥锁


1.pthread_mutex_init


头文件:#include 
原型:int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
功能:动态初始化一把锁
参数:mutex:锁变量的地址
attr:互斥所得属性,NULL缺省默认
返回值:
总是返回 0


2. 静态初始化一把锁


pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;


3. pthread_mutex_lock


头文件:#include 
原型:int pthread_mutex_lock(pthread_mutex_t *mutex);
功能:尝试枷锁,如果没有抢到锁资源,阻塞等待加锁
参数:mutex:锁变量的地址
返回值:
成功返回 0
失败返回非0


4.pthread_mutex_trylock


头文件:#include 
原型:int pthread_mutex_trylock(pthread_mutex_t *mutex);
功能:尝试加锁,如果没有抢到锁资源,报错返回
参数:mutex:锁变量的地址
返回值:
成功返回 0
失败返回非0


5.pthread_mutex_unlock


头文件:#include 
原型:int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:解锁操作
参数:mutex:锁变量的地址
返回值:
成功返回 0
失败返回非0


6. pthread_mutex_destroy


头文件:#include 
原型:int pthread_mutex_destroy(pthread_mutex_t *mutex);
功能:销毁一把锁
参数:mutex:锁变量的地址
返回值:
成功返回 0
失败返回非0


练习


目标将全局变量a加到100 0000,使用两个线程去做,每个线程应该各加50 0000次,这种情况还需要同步吗?


#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
int count = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void * myfun(void * arg)
{
    int i = 500000;
    while(i)
    {
        if(-1 == pthread_mutex_lock(&mutex))
        {
            perror("lock");
            return NULL;
        }
        //临界区 ---》开始
        int a = count;
        a++;
        count = a; 
        //临界区 ---》结束
        if(-1 == pthread_mutex_unlock(&mutex))
        {
            perror("lock");
            return NULL;
        }
        i--;
    }
}
int main(int argc, char const *argv[])
{
    pthread_t tid = 0;
    if(0 != pthread_create(&tid,NULL,myfun,NULL))
    {
        perror("create");
        return -1;
    }
    int i = 500000;
    while(i)
    {
        if(-1 == pthread_mutex_lock(&mutex))
        {
            perror("lock");
            return -1;
        }
        int a = count;
        a++;
        count = a;
        if(-1 == pthread_mutex_unlock(&mutex))
        {
            perror("lock");
            return -1;
        }
        i--;
    }
    pthread_join(tid,NULL);
    pthread_mutex_destroy(&mutex);
    printf("count = %d\n",count);
    return 0;
}


练习


卖票,共一百张票,有5个人一起卖,设计5个线程,使其票不能重复卖出,并且打印出是哪个线程卖得第多少张票?


#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int Ticket = 100;
pthread_mutex_t mutex;
void delay()
{
    int x = 10000,y;
    while(x--)
    {
        y = 5000;
        while(y--);
    }
}
void * SaleTicket(void *arg)
{
    int cur_ticket;
    while (1)
    {
        pthread_mutex_lock(&mutex);
        cur_ticket = Ticket;
        if(cur_ticket <=0)
        {
            pthread_mutex_unlock(&mutex);
            break;
        }
        printf("%ld get %d-th ticket!\n",pthread_self(),cur_ticket);
        cur_ticket--;
        Ticket = cur_ticket;
        pthread_mutex_unlock(&mutex);
        delay();
    }
}
int main(int argc, char const *argv[])
{
    int i,ret;
    pthread_t tid[5] = {0};
    pthread_mutex_init(&mutex,NULL);  //动态初始化一把锁
    for(i = 0; i < 5;i++)
    {
        ret = pthread_create(&tid[i],NULL,SaleTicket,NULL);
        if(ret != 0)
        {
            perror("create");
            return -1;
        }
    }
    for(i = 0; i < 5;i++)
    {
        void *status;
        pthread_join(tid[i],&status); 
    }
    pthread_mutex_destroy(&mutex);
    return 0;
}


1.5 条件变量


条件变量是为了完成线程间同步指定出来得一种机制,是利用将一个线程挂起等待。然后由另一方发送一个条件成立得信号将其唤醒继续运行得原理。

缺点:等待一方必须要先获取到锁。


1.5.1 函数的接口


1.静态初始化条件变量


pthread_cond_t cond = PTHREAD_COND_INITIALIZER;


2.动态初始化条件变量


头文件:#include 
原型:int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
功能:动态初始化条件变量
参数:cond:条件变量的地址
attr:使用缺省模式NULL
返回值:
成功返回 0
失败返回非0


3.pthread_cond_wait


头文件:#include 
原型:int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
功能:主动挂起等待信号的到来
参数:cond:条件变量的地址
mutex:锁变量的地址
注意:wait函数和一把锁一起绑定,当这个函数运行后,
1.先进性解锁操作,让这把锁的使用权
2.然后将线程挂起
3.当信号到来时,准备运行之前,需要先尝试加锁
1,2属于原子操作
返回值:
成功返回 0
失败返回非0

4.pthread_cond_signal

头文件:#include 
原型:int pthread_cond_signal(pthread_cond_t *cond);
功能:发送一个条件成立的信号,一次性的,每次只能唤醒一个线程,谁收到谁执行
参数:cond:条件变量的地址
返回值:
成功返回 0
失败返回非0

5. pthread_cond_broadcast

头文件:#include 
原型:int pthread_cond_broadcast(pthread_cond_t *cond);
功能:发送一个条件成立的信号,唤醒所有等待的线程,一个广播信号
参数:cond:条件变量的地址
返回值:
成功返回 0
失败返回非0

6. pthread_cond_destory

头文件:#include 
原型:int pthread_cond_destory(pthread_cond_t *cond);
功能: 销毁一个条件变量
参数:cond:条件变量的地址
返回值:
成功返回 0
失败返回非0


#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int Ticket = 100;
pthread_mutex_t mutex;
pthread_cond_t cond;
void delay()
{
    int x = 10000,y;
    while(x--)
    {
        y = 5000;
        while(y--);
    }
}
void * SaleTicketA(void *arg)
{
    int cur_ticket;
    while (1)
    {
        pthread_mutex_lock(&mutex);
        cur_ticket = Ticket;
        if(cur_ticket <=0)
        {
            pthread_mutex_unlock(&mutex);
            break;
        }
        if(cur_ticket == 50)
        {
            pthread_cond_signal(&cond);  //唤醒另一个线程
        }
        printf("A get %d-th ticket!\n",cur_ticket);
        cur_ticket--;
        Ticket = cur_ticket;
        pthread_mutex_unlock(&mutex);
        delay();
    }
}
void * SaleTicketB(void *arg)
{
    int cur_ticket;
    while (1)
    {
        pthread_mutex_lock(&mutex);
        cur_ticket = Ticket;
        if(cur_ticket <=0)
        {
            pthread_mutex_unlock(&mutex);
            break;
        }
        if(cur_ticket >= 50)
        {
            pthread_cond_wait(&cond,&mutex);  //释放互斥锁,进入睡眠状态
            cur_ticket = Ticket;
        }
        printf("B get %d-th ticket!\n",cur_ticket);
        cur_ticket--;
        Ticket = cur_ticket;
        pthread_mutex_unlock(&mutex);
        delay();
    }
}
int main(int argc, char const *argv[])
{
    int i,ret;
    pthread_t tid[2] = {0};
    pthread_mutex_init(&mutex,NULL);  //动态初始化一把锁
    pthread_cond_init(&cond,NULL);  //初始化条件变量
    ret = pthread_create(&tid[0],NULL,SaleTicketA,NULL);
    if(ret != 0)
    {
        perror("create");
        return -1;
    }
    ret = pthread_create(&tid[1],NULL,SaleTicketB,NULL);
    if(ret != 0)
    {
        perror("create");
        return -1;
    }  
    for(i = 0; i < 2;i++)
    {
        void *status;
        pthread_join(tid[i],&status); 
    }
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    return 0;
}
相关文章
|
16天前
|
搜索推荐 索引
【文件IO】实现:查找文件并删除、文件复制、递归遍历目录查找文件
【文件IO】实现:查找文件并删除、文件复制、递归遍历目录查找文件
29 2
|
16天前
|
编解码 Java 程序员
【文件IO】文件内容操作
【文件IO】文件内容操作
34 2
|
16天前
|
存储 Java API
【文件IO】文件系统操作
【文件IO】文件系统操作
36 1
|
1月前
|
Java 大数据 API
Java 流(Stream)、文件(File)和IO的区别
Java中的流(Stream)、文件(File)和输入/输出(I/O)是处理数据的关键概念。`File`类用于基本文件操作,如创建、删除和检查文件;流则提供了数据读写的抽象机制,适用于文件、内存和网络等多种数据源;I/O涵盖更广泛的输入输出操作,包括文件I/O、网络通信等,并支持异常处理和缓冲等功能。实际开发中,这三者常结合使用,以实现高效的数据处理。例如,`File`用于管理文件路径,`Stream`用于读写数据,I/O则处理复杂的输入输出需求。
|
17天前
|
存储 Java 程序员
【Java】文件IO
【Java】文件IO
30 0
|
1月前
|
Linux C语言
C语言 文件IO (系统调用)
本文介绍了Linux系统调用中的文件I/O操作,包括文件描述符、`open`、`read`、`write`、`lseek`、`close`、`dup`、`dup2`等函数,以及如何获取文件属性信息(`stat`)、用户信息(`getpwuid`)和组信息(`getgrgid`)。此外还介绍了目录操作函数如`opendir`、`readdir`、`rewinddir`和`closedir`,并提供了相关示例代码。系统调用直接与内核交互,没有缓冲机制,效率相对较低,但实时性更高。
|
2月前
|
存储 监控 Linux
性能分析之从 IO 高定位到具体文件
【8月更文挑战第21天】性能分析之从 IO 高定位到具体文件
34 0
性能分析之从 IO 高定位到具体文件
|
2月前
IO流拷贝文件的几种方式
IO流拷贝文件的几种方式
34 1
|
3月前
|
Linux 数据处理 C语言
【Linux】基础IO----系统文件IO & 文件描述符fd & 重定向(下)
【Linux】基础IO----系统文件IO & 文件描述符fd & 重定向(下)
69 0
|
3月前
|
Linux C语言 C++
【Linux】基础IO----系统文件IO & 文件描述符fd & 重定向(上)
【Linux】基础IO----系统文件IO & 文件描述符fd & 重定向(上)
45 0