zoukankan      html  css  js  c++  java
  • linux线程同步(队列方式)

    看了一些关于信号量的线程同步方式,今天用了一下。

    我对于线程同步一直有疑问,在主线程和子线程处理时间不相同的时候,用这种信号量,如何保证同步。

    假如主线程比较快,信号量连加了n个,但是子线程就不断减这个n,减到0。但是如果主线程太快太快,需要停一停,比如缓冲区快溢出了,主线程需要挂起。

    由什么来唤醒主线程呢?子线程?不过这样的话,容易造成主线程死锁,或者主和子都卡死。

    下面的程序,没有用到信号量同步,信号量只是负责开启子线程而已。主要是队列的实现而已。等我把上面的问题解决完会写上更新的程序。

    队列头文件:

    #ifndef _queue_H
    #define _queue_H
    
    typedef int T;
    typedef struct queue Queue;
    struct queue{
        T data;
        Queue* next;
    };
    
    static int length=0;
    
    Queue* CreateQueue();
    void DestroyQueue(Queue* h);
    int Push(Queue* h,T t);
    Queue* Pop(Queue* h);
    void Print(Queue* h);
    
    
    #endif

    队列c文件:

    #include <stdio.h>
    #include <stdlib.h>
    #include "queue.h"
    
    const int MaxSize=50;
    
    Queue* CreateQueue()
    {
        Queue* h=(Queue*)malloc(sizeof(Queue));
        if(h==NULL)
        {
            printf("Malloc failed!
    ");
            return NULL;
        }
        h->next=NULL;
        return h; 
    }
    
    void DestroyQueue(Queue* h)
    {
        Queue* p=h;
        while(p!=NULL)
        {
            Queue* tmp=p;
            p=p->next;
            free(tmp);
        }
    }
    
    int Push(Queue* h,T t)
    {
        Queue* tmp=(Queue*)malloc(sizeof(Queue));
        if(tmp==NULL)
        {
            printf("Malloc failed!
    ");
            return;
        }
        tmp->data=t;
        tmp->next=NULL;
        
        if(length>=MaxSize)
        {
            printf("Queue is full!
    ");
            return -1;
        }
        Queue* p=h;
        while(p->next!=NULL)
        {
            p=p->next;
        }
        p->next=tmp;
        length++;
    }
    
    Queue* Pop(Queue* h)
    {
        Queue* res=h->next;
        if(h->next==NULL)
        {
            //printf("Queue is empty!
    ");
            return NULL;
        }
        h->next=h->next->next;
        length--;
        return res;
    }
    
    void Print(Queue* h)
    {
        Queue* p=h->next;
        while(p!=NULL)
        {
            printf("%d
    ",p->data);
            p=p->next;
        }
        printf("Above is the Queue!
    ");
        printf("
    ");
    }

    主程序:

    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include <semaphore.h>
    #include "queue.h"
    
    /*
    此程序模仿生产者-消费者模型
    生产者:0-99的int型数,进入队列。如果队列(默认最大50)满了,提示已满,主线程等待直到队列可以进入。
    消费者:对生产者产生的数据计算并输出10个结果。如果队列空了,提示已空。
    通过队列和信号量来同步。
    此程序以主线程为主,因为相互发信号会导致死锁,程序卡住!应该是技术不够,不过也至于冒这个险!
    */
    
    sem_t btn_sem;//二进制信号量
    sem_t flag_sem;
    Queue *head;//队列头部
    int End=0;//主线程结束标志位
    
    //子线程执行函数
    void *thread_func(void *arg)
    {
        int i=0; 
        sem_wait(&btn_sem);//子线程等待开始
        while(1)
        {    
            Queue *tmp=Pop(head);
            if(tmp==NULL)//队列已经空了
            {
            }
            else
            {
                printf("Chlid Thread! ");
                for(i=tmp->data;i<tmp->data+10;i++)
                {
                    printf("%d ",i);
                }
                printf("
    ");//子线程输出
                free(tmp);
            }
            if(End==1)
            {
                if(head->next==NULL)
                    return;
            }
        }    
    }
    
    int main()
    {
        head=CreateQueue();
        int i=0;
        char aa[]="aaaa!";
        pthread_t a_thread;
    
        int res;
        res=sem_init(&btn_sem,0,0);
        if(res!=0)
        {
            printf("Signal initials failed!
    ");
            return;
        }
        res=sem_init(&flag_sem,0,0);
        if(res!=0)
        {
            printf("Signal initials failed!
    ");
            return;
        }
        res=pthread_create(&a_thread,NULL,thread_func,(void*)aa);
        if(res!=0)
        {
            printf("Create thread failed!
    ");
            return;
        }
    
        sem_post(&btn_sem);//第一次进入主循环时发信号,告知子线程可以开始
        //主线程,生产者
        for(i=0;i<100;i++)
        {
            res=Push(head,i);//数据直接进入队列
            if(res==-1)//如果队列满了,需要等待
            {
                while(Push(head,i)==-1);//放到队列有空间为止
                //Push(head,i);//子线程发信号,表示队列有空间了,此时把等待的信息push进队列
            }
            printf("%d
    ",i);
        }
        End=1;
    
        void *thread_res;
        pthread_join(a_thread,&thread_res);//等待子线程结束后,结束主线程
        sem_destroy(&btn_sem);
        sem_destroy(&flag_sem);
    
        DestroyQueue(head);
        return 0;
    }

    makefile:

    main:main.o queue.o
        gcc -o main main.o queue.o -pthread
    
    main.o:main.c queue.h
        gcc -c main.c -pthread
    
    queue.o:queue.c queue.h
        gcc -c queue.c

    如果队列满了,这里不采用等待子线程做,而是不断访问队列,等待队列有空间,其实也就是等待子线程操作。

    不过这种方式不好!

    因为主线程其实还是一直在做自己的事情,CPU并不知道此时需要少分时间片给主线程,而是按照正常的分配给主和子。

    理想情况,此时应该主线程挂起,主要给子线程,让其运行,产生多余的队列空间。

    所以以上程序的效率是不高的。

  • 相关阅读:
    手把手教你如何逐步安装OpenStack
    掌握OpenStack部署的最佳实践 打破部署失败的魔咒
    大数据服务大比拼:AWS VS. AzureVS.谷歌
    fullcalender
    也谈---基于 HTTP 长连接的“服务(转载)
    调用页面脚本
    mssql 低版本数据库 使用高版本的命令
    行变列 pivot
    HighCharts -在包含容器尺寸发生变化时重新渲染
    ES6 import export
  • 原文地址:https://www.cnblogs.com/wyc199288/p/5475478.html
Copyright © 2011-2022 走看看