多线程

本文通过一个家庭成员放置和食用苹果与梨子的场景,深入浅出地讲解了线程同步的概念及其实现方式。在一个限定容量的果盘中,爸爸放置苹果,女儿食用苹果;妈妈放置梨子,儿子食用梨子。使用信号量和互斥锁确保了资源的正确访问,避免了竞态条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 爸爸放苹果,女儿吃苹果,必须有苹果才能吃(线程同步)
  2. 妈妈放梨子,儿子吃梨子,不许有梨子才能吃(线程同步)
  3. 果盘中最多能放20个水果,多了不能放

eatFruit.c

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
#include "type.h"
#include "eatFruit.h"
#include "output.h"

sem_t sem_remain, sem_apple, sem_pear, mutex;
EAT_FRUIT_S g_eat_fruit = {0};
FRUIT_NUM_S g_fruit_num = {0};

void sem_info_print()
{
    int32 value = 0;
    EAT_FRUIT_S *p_eat_info = &g_eat_fruit;

    sem_getvalue(p_eat_info->p_sem_remain, &value);
    DEBUG_OUTPUT("remain sem is %d\r\n", value);

    sem_getvalue(p_eat_info->p_sem_apple, &value);
    DEBUG_OUTPUT("apple sem is %d\r\n", value);

    sem_getvalue(p_eat_info->p_sem_pear, &value);
    DEBUG_OUTPUT("pear sem is %d\r\n", value);

    sem_getvalue(p_eat_info->p_mutex, &value);
    DEBUG_OUTPUT("mutex sem is %d\r\n", value);
}

EAT_FRUIT_S *get_eat_fruit_info()
{
    return &g_eat_fruit;
}

FRUIT_NUM_S *get_fruit_num_info()
{
    return &g_fruit_num;
}

uint32 eat_fruit_uninit()
{
    sem_destroy(&sem_remain);
    sem_destroy(&sem_apple);
    sem_destroy(&sem_pear);
    sem_destroy(&mutex);
}

uint32 eat_fruit_init()
{
    EAT_FRUIT_S *p_eat_info = get_eat_fruit_info();
    FRUIT_NUM_S *p_num_info = get_fruit_num_info();

    p_num_info->remain = 20;
    p_num_info->apple  = 0;
    p_num_info->pear   = 0;
    p_eat_info->p_sem_remain = &sem_remain;
    p_eat_info->p_sem_apple  = &sem_apple;
    p_eat_info->p_sem_pear   = &sem_pear;
    p_eat_info->p_mutex      = &mutex;

    sem_init(&sem_remain, 0, p_num_info->remain);
    sem_init(&sem_apple, 0, p_num_info->apple);
    sem_init(&sem_pear, 0, p_num_info->pear);
    sem_init(&mutex, 0, 1);

    return 0;
}

void *father(void *p_para)
{
    EAT_FRUIT_S *eat_info = NULL;
    FRUIT_NUM_S *num_info = NULL;
    
    DEBUG_OUTPUT("[father] function execute\r\n");
    eat_info = get_eat_fruit_info();

    while(1)
    {
        sem_wait(eat_info->p_sem_remain);
        sem_wait(eat_info->p_mutex);
        num_info = get_fruit_num_info(); /* critical resource must got in mutex */
        DEBUG_OUTPUT("[father]Before place apple, remain = %u, apple = %u\r\n", num_info->remain--, num_info->apple++);
        DEBUG_OUTPUT("[father]After  place apple, remain = %u, apple = %u\r\n", num_info->remain, num_info->apple);
        sem_post(eat_info->p_mutex);
        sem_post(eat_info->p_sem_apple);
        sleep(1);
    }
}

void *mother(void *para)
{
    EAT_FRUIT_S *eat_info = NULL;
    FRUIT_NUM_S *num_info = NULL;
    
    DEBUG_OUTPUT("[mother] function execute\r\n");
    eat_info = get_eat_fruit_info();
    while(1)
    {
        sem_wait(eat_info->p_sem_remain);
        sem_wait(eat_info->p_mutex);
        num_info = get_fruit_num_info(); /* critical resource must got in mutex */
        DEBUG_OUTPUT("[mother]Before place pear, remain = %u, pear = %u\r\n", num_info->remain--, num_info->pear++);
        DEBUG_OUTPUT("[mother]After  place pear, remain = %u, pear = %u\r\n", num_info->remain, num_info->pear);
        sem_post(eat_info->p_mutex);
        sem_post(eat_info->p_sem_pear);
        sleep(2);
    }
}

void *son(void *para)
{
    EAT_FRUIT_S *eat_info = NULL;
    FRUIT_NUM_S *num_info = NULL;
    
    DEBUG_OUTPUT("[son] function execute\r\n");
    eat_info = get_eat_fruit_info();
    while(1)
    {
        sem_wait(eat_info->p_sem_pear);
        sem_wait(eat_info->p_mutex);
        num_info = get_fruit_num_info(); /* critical resource must got in mutex */
        DEBUG_OUTPUT("[son]Before eat pear, remain = %u, pear = %u\r\n", num_info->remain++, num_info->pear--);
        DEBUG_OUTPUT("[son]After  eat pear, remain = %u, pear = %u\r\n", num_info->remain, num_info->pear);
        sem_post(eat_info->p_mutex);
        sem_post(eat_info->p_sem_remain);
        sleep(3);
    }
}

void *daughter(void *p_para)
{
    EAT_FRUIT_S *eat_info = NULL;
    FRUIT_NUM_S *num_info = NULL;
    
    DEBUG_OUTPUT("[daughter] function execute\r\n");
    eat_info = get_eat_fruit_info();
    while(1)
    {
        sem_wait(eat_info->p_sem_apple);
        sem_wait(eat_info->p_mutex);
        num_info = get_fruit_num_info(); /* critical resource must got in mutex */
        DEBUG_OUTPUT("[daughter]Before eat apple, remain = %u, apple = %u\r\n", num_info->remain++, num_info->apple--);
        DEBUG_OUTPUT("[daughter]After  eat apple, remain = %u, apple = %u\r\n", num_info->remain, num_info->apple);
        sem_post(eat_info->p_mutex);
        sem_post(eat_info->p_sem_remain);
        sleep(3);
    }
}

int32 eat_fruit_create_thread(pthread_t *p_thread, void *func(void *), int8 *p_name)
{
    int32 ret = 0;
    ret = pthread_create(p_thread, NULL, func, NULL);
    if (ret != 0)
    {
        DEBUG_OUTPUT("[main]%s pthread create failed\r\n", p_name);
        return ret;
    }

    return ret;
}

int32 main(int32 argc, int8 *argv[])
{
    int32 ret;
    uint32 i;
    pthread_t thread[4];
    int8 *name[4] = {"father", "mother", "son", "daughter"};
    CALLBACK_FUN call_back_func[4] = {father, mother, son, daughter};
    // void *(*call_back_func[4])(void *) = {father, mother, son, daughter};

    eat_fruit_init();
    sem_info_print();

    for (i = 0; i < 4; i++)
    {
        eat_fruit_create_thread(&thread[i], call_back_func[i], name[i]);
    }

    while(1)
    {
        ;
    }
    return 0
}

eatFruit.h

#ifndef __EAT_FRUIT__
#define __EAT_FRUIT__
typedef void *(* CALLBACK_FUN)(void *);

typedef struct EatFruit
{
    sem_t *p_sem_remain;
    sem_t *p_sem_apple;
    sem_t *p_sem_pear;
    sem_t *p_mutex;  /* used for access FRUIT_NUM_S */
}EAT_FRUIT_S;

typedef struct FruitNum
{
    uint32 remain;
    uint32 apple;
    uint32 pear;
}FRUIT_NUM_S;
#endif

type.h

#ifndef __TYPE_H__
#define __TYPE_H__
typedef int int32;
typedef unsigned int uint32;
typedef char int8;
typedef unsigned char uint8;
#endif

output.h

#ifndef __OUTPUT_H__
#define __OUTPUT_H__
typedef int int32;
typedef unsigned int uint32;
typedef char int8;
typedef unsigned char uint8;
#endif

void debug_print(int8 *fmt, ...);

#define DEBUG_OUTPUT(fmt, ...) \
    debug_print("(%s)"fmt, __TIME__, ##__VA_ARGS__);
#endif

output.c

#include <stdio.h>
#include <stdarg.h>
#include "type.h"

void debug_print(int8 *fmt, ...)
{
    va_list arg;
    int8 local_buf[100] = {0};

    va_start(arg, fmt);
    (void)vsprintf(local_buf, fmt, arg);
    printf("%s\r\n", local_buf);
    va_end(arg);
    return;
}

makefile

CC=gcc
ROOT = /repo/ezheson/test_dm/eat_fruit
SRC_FILES = $(ROOT)/src/eatFruit.c \
            $(ROOT)/src/output.c
OBJECTS=$(SRC_FILES:$(ROOT)/src/%.c=$(ROOT)/build/%.o)    ## 替换src/*.c成build/*.o
INCLUDE:=-I$(ROOT)/inc

FLAGS=-lpthread

eatFruit.out:$(OBJECTS)
 $(CC) $(FLAGS) $^ -o $@

$(OBJECTS):$(ROOT)/build/%.o:$(ROOT)/src/%.c
 $(CC) $(INCLUDE) -c $< -o $@

.PHONY:clean
clean:
 rm -rf *.out; cd build; rm -rf *.o

运行结果
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值