Linux中joinable(结合线程)消费者和生产者模型

**

Linux中joinable和原子、互斥锁的操作

**
注:线程默认是joinable(结合线程),本次使用的是进程间同步信号量操作。

使用分文件编程思想,定义工厂头文件 “product.h”

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

typedef struct Nodes
{
    int num;
    struct Nodes *next;
} Nodes;

union semun
{
    int value;
};
int sem_Init(int sem_Id, int value);
int sem_Del(int sem_Id);
int sem_P(int sem_Id);
int sem_V(int sem_Id);
~                      

2.关于信号量PV操作,实现函数如下product.c

#include "product.h"

int sem_Init(int sem_Id, int value)
{
    union semun sem_union;
    sem_union.value = value;
    if((semctl(sem_Id, 0 ,SETVAL, sem_union)) == -1)
    {
        perror("semctl");
        return -1;
    }
    return 0;
}
int sem_Del(int sem_Id)
{
    union semun sem_union;
    if((semctl(sem_Id, 0 , IPC_RMID, sem_union))== -1)
    {
        perror("semdel");
        return -1;
    }
    return 0;
}
int sem_P(int sem_Id)
{
    struct sembuf sem_buf;
    sem_buf.sem_num = 0;
    sem_buf.sem_op  =-1;
    sem_buf.sem_flg =SEM_UNDO;
    if((semop(sem_Id, &sem_buf, 1))==-1)
    {
        perror("sem_p");
        return -1;
    }
    return 0;
}
int sem_V(int sem_Id)
{
    struct sembuf sem_buf;
    sem_buf.sem_num = 0;
    sem_buf.sem_op = 1;
    sem_buf.sem_flg = SEM_UNDO;
    if((semop(sem_Id,&sem_buf, 1))==-1)
    {
        perror("sem_v");
        return -1;
    }
    return 0;

}

3.创建生产者和消费者线程,开启线程。

注:使用链表,手动输入内容作为工厂的“ 实物链 ”,让消费者合理有序“ 消费 ”,退出时无内存泄漏。

#include "product.h"

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

static int sem_Id;
Nodes *head = NULL;

Nodes *createNodes()
{
    Nodes *nodes = (Nodes *)malloc(sizeof(Nodes));
    nodes->next = NULL;
    return nodes;
}
Nodes *addTail()
{
    Nodes *tempNode = head;
    Nodes *newNode = NULL;
    newNode = createNodes();
    if (NULL == head)
    {
        head = newNode;
        return head;
    }
    else
    {
        while (tempNode->next != NULL)
        {
            tempNode = tempNode->next;
        }
		tempNode->next = newNode;
        newNode->next = NULL;
        return newNode;
    }
}
void deleNode(Nodes *newNode)
{
    Nodes *temp = NULL;
    if (NULL == newNode)
    {
        return;
    }
    else if (newNode == head)
    {
        temp = head->next;
        free(newNode);
        head = temp;
    }
    else
    {
        temp = head->next;
        free(head);
    }
}
void printids(const char *s)
{
    pid_t pid;
    pthread_t tid;
    pid = getpid();
    tid = pthread_self();
    printf("%s :pid :%d tid :%d\n", s, (unsigned int)pid, (unsigned int)tid);
}
void printNode(Nodes *head)
{
    Nodes *temp = head;
    if (NULL == head)
    {
        printf("head is NULL! \n");
        return;
    }
    else
    {
        while (temp != NULL)
        {
            printf("get datas is %d \n", temp->num);
            temp = temp->next;
        }
    }
}
void *thread_producter(void *arg)
{
    int i;
    int flag;
    int x;
 Nodes *newNode = head;
    printids("start thread_producter!\n");
    pthread_mutex_lock(&mutex);
    for (i = 0; i < 5; i++)
    {
        newNode = addTail();
        printf("Please input %d number info:\n", i);
        x = scanf("%d", &flag);
        if (x)
        {
            newNode->num = flag;
        }
        else
        {
            printf("input error!\n");
            break;
        }
    }
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);
}
void *thread_con1(void *arg)
{
    int i=0;
    pthread_mutex_lock(&mutex);
    pthread_cond_wait(&cond, &mutex);
    printids("thread_consumer_one start!");
    pthread_mutex_unlock(&mutex);
 	sem_V(sem_Id);
 	//该处放置锁,有两种情况。一种是被第二个消费者拿走,那么我们需要第二个消费拿完放回锁,让这个消费者继续运行,达到指定内容,让第二个消费者进行消费。还有一种情况是在当下继续运行。
    sem_P(sem_Id);
    while (head != NULL)
    {
        printf("consumer one get node msg:%d\n", head->num);
        deleNode(head);
        if(i == 2)
        {
            sem_V(sem_Id);
        }
        sleep(1);
        i++;
    }
}
void *thread_con2(void *arg)
{
    sem_P(sem_Id);
    printids("thread_consumer_two start!");
    sem_V(sem_Id);
    sem_P(sem_Id);
    while (head != NULL)
    {
        printf("consumer two get node msg:%d\n", head->num);
        deleNode(head);
    }
    sem_V(sem_Id);
}
int main(int argc, char **argv)
{
    int err;
    void *ret;

    pthread_t thr_joinable_producter;
    pthread_t thr_consumer_one;
    pthread_t thr_consumer_two;

    sem_Id = semget(ftok(".", 1), 1, IPC_CREAT | 0666);
    if (0 == sem_Id)
    {
        printf("semget success! \n");
    }
    else
    {
        printf("semget failed:%s\n", strerror(sem_Id));
    }
    sem_Init(sem_Id, 0);
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);

    err = pthread_create(&thr_joinable_producter, NULL, thread_producter, NULL);
    if (0 != err)
    {
        printf("pthread_create failed: %s\n", strerror(err));
    }
    else
        {
        printf("thr_producter start success!\n");
    }

    err = pthread_create(&thr_consumer_one, NULL, thread_con1, NULL);
    if (0 != err)
    {
        printf("thr_consumer_one failed:%s\n", strerror(err));
    }
    else
    {
        printf("thr_consumer_one success! \n");
    }
    err = pthread_create(&thr_consumer_two, NULL, thread_con2, NULL);
    if (0 != err)
    {
        printf("thr_consumer_two failed:%s\n", strerror(err));
    }
    else
    {
       else
    {
        printf("thr_consumer_two success! \n");
    }
    pthread_join(thr_consumer_one, &ret);
    pthread_join(thr_consumer_two, &ret);
    pthread_join(thr_joinable_producter, &ret);
    //注意释放资源,也就是销毁锁。
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    sem_Del(sem_Id);

    return 0;
}
                                     

4.Makefile的编写

TARGET=test
CC=gcc
INCLUDE=./
LIBS=-lpthread
OBJS=main.o product.o
${TARGET}:${OBJS}
        ${CC} -o ${TARGET} ${OBJS} ${LIBS}
main.o:main.c
        ${CC} -c main.c
product.o:product.c
        ${CC} -c product.c
.PHONY:clean
clean:
        rm -f *.o ${TARGET}

注意事项:前面目标文件以及虚拟引用,后面必须使用 = 不是冒号

TARGET=test
CC=gcc
INCLUDE=./
LIBS=-lpthread
OBJS=main.o product.o

在生成目标文件的指令时,所需要的依赖.0文件必须添加在后面,以及所使用的链接库。

${TARGET}:${OBJS}
        ${CC} -o ${TARGET} ${OBJS} ${LIBS}

5.实验现象:

生产者消费者模型

6.关于线程

对于可连接的线程而言,它不会自动释放其内存空间,必须对该线程使用 pthread_join()才能释放其内存空间。

对于可分离的线程而言,该线程运行结束后会自动释放所有资源。

可以看出pthread_join()有两种作用:
用于等待其他线程结束:当调用 pthread_join() 时,当前线程会处于阻塞状态,直到被调用的线程结束后,当前线程才会重新开始执行。
对线程的资源进行回收:如果一个线程是非分离的(默认情况下创建的线程都是非分离)并且没有对该线程使用 pthread_join() 的话,该线程结束后并不会释放其内存空间,这会导致该线程变成了“僵尸线程”。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值