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!\n");
        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!\n");
        return;
    }
    tmp->data=t;
    tmp->next=NULL;

    if(length>=MaxSize)
    {
        printf("Queue is full!\n");
        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!\n");
        return NULL;
    }
    h->next=h->next->next;
    length--;
    return res;
}

void Print(Queue* h)
{
    Queue* p=h->next;
    while(p!=NULL)
    {
        printf("%d\n",p->data);
        p=p->next;
    }
    printf("Above is the Queue!\n");
    printf("\n");
}

主程序:

#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("\n");//子线程输出
            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!\n");
        return;
    }
    res=sem_init(&flag_sem,0,0);
    if(res!=0)
    {
        printf("Signal initials failed!\n");
        return;
    }
    res=pthread_create(&a_thread,NULL,thread_func,(void*)aa);
    if(res!=0)
    {
        printf("Create thread failed!\n");
        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\n",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并不知道此时需要少分时间片给主线程,而是按照正常的分配给主和子。

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

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

时间: 2024-12-09 18:52:36

linux线程同步(队列方式)的相关文章

实现线程同步的方式,以及区别

19.实现线程同步的方式,以及区别 为何要使用同步? java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),    将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用,    从而保证了该变量的唯一性和准确性.    同步的方式 1.同步方法    即有synchronized关键字修饰的方法.    由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,    内置锁会保护整个方法.在调用该方法前,需

使用信号量控制Linux线程同步

线程同步 在现实生活中,有些东西就必须是按顺序执行的,只有我完成了以后,你才能在我的劳动成果上接着干:不能我还没有完成,你就开始干活了.这就是线程同步最直白的解释了. 在进行程序设计时,亦是如此.线程同步,同步的是什么?它同步的是对共享资源(内存区域,公共变量等)或者临界区域的访问.有的时候,这些共享 资源和临界区域,就只能容忍一个线程对它进行操作(读或者写,读操作一般不控制,主要是写操作),这个时候,我们必须要对这些共享资源或者临界区域进行同 步,那么如何对它们进行线程同步呢? 在Linux中

操作系统:进程/线程同步的方式和机制,进程间通信

一.进程/线程间同步机制. 临界区.互斥区.事件.信号量四种方式临界区(Critical Section).互斥量(Mutex).信号量(Semaphore).事件(Event)的区别1.临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问.在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开,临界区在被释放后,其他线程才可以抢占.2.互斥量:采用互斥对象机

进程/线程同步的方式和机制,进程间通信

转自: http://www.cnblogs.com/memewry/archive/2012/08/22/2651696.html 一.进程/线程间同步机制. 临界区.互斥区.事件.信号量四种方式临界区(Critical Section).互斥量(Mutex).信号量(Semaphore).事件(Event)的区别1.临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问.在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后

【转】 Linux 线程同步的三种方法

线程的最大特点是资源的共享性,但资源共享中的同步问题是多线程编程的难点.linux下提供了多种方式来处理线程同步,最常用的是互斥锁.条件变量和信号量. 一.互斥锁(mutex) 通过锁机制实现线程间的同步. 初始化锁.在Linux下,线程的互斥量数据类型是pthread_mutex_t.在使用前,要对它进行初始化.静态分配:pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;动态分配:int pthread_mutex_init(pthread_m

Java线程同步的方式

java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查), 将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用, 从而保证了该变量的唯一性和准确性. 1.同步方法 即有synchronized关键字修饰的方法. 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 内置锁会保护整个方法.在调用该方法前,需要获得内置锁,否则就处于阻塞状态. 代码如: public synchronized void sav

Linux线程同步

线程同步-互斥锁 1.初始化互斥锁pthread_mutex_init() int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); 例: pthread_mutex_t mutex; pthread_mutex_init(&mutex, NULL); 2.锁住互斥锁pthread_mutex_lock() int pthread_mutex_lock(pt

Linux线程同步---信号量

首先讲一下线程同步信号量的几个关键步骤! 1.定义并初始化信号量. (1) sem_t bin_sem; (2)  res = sem_init(&bin_sem,0,0); 详细步骤可以查看man帮助页面 2.使用信号量 (1) 信号量加1操作.sem_post(&bin_sem); (2) 信号量等待并减1操作.sem_wait(&bin_sem); 初始化后一般处于等待状态,执行某个操作后加1,而另个一个操作执行前进行等待操作.如果有多个线程,通常是一个线程进行加1操作,另外

LINUX线程同步初探

0x00.什么是线程同步 同步,又称直接制约关系,是指多个线程(或进程)为了合作完成任务,必须严格按照规定的 某种先后次序来运行 0x01.案例代码 1 void* PthreadFunc(void* argc); 2 int flag_num = 1; 3 4 int main(int argc, char* argv[]) 5 { 6 pthread_t pid; 7 void* ret_val; 8 9 int create_status = pthread_create(&pid, NU