Producer- und Consumer-Thread-Schleife


Fügen Sie hier eine Bildbeschreibung ein

Referenz

Referenz: Thread-sichere Warteschlangen

Beachten

pthread_mutex_t Mutex-Sperre

  • PTHREAD_MUTEX_INITIALIZERBei der Initialisierung mit ist der Standardzustand entsperrt (d. h. entsperrter Zustand) . Diese Methode erstellt eine statisch initialisierte Mutex-Sperre, die für die Initialisierung statischer globaler Variablen oder statischer lokaler Variablen geeignet ist.
  pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;			//未锁定的(即解锁状态)
  • Wenn Sie die Funktion zur Initialisierung verwenden pthread_mutex_init, können Sie den Ausgangszustand durch Angabe von Attributparametern bestimmen. Wenn der Attributparameter lautet , ist der Mutex NULLstandardmäßig entsperrt . Wenn Sie es in einem gesperrten Zustand erstellen müssen, können Sie pthread_mutexattr_settypedie Funktion verwenden, um die Eigenschaft auf festzulegen PTHREAD_MUTEX_INITIALIZER.

    pthread_mutex_t mutex;
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_INITIALIZER); // 设置属性为初始化器;指定互斥锁的初始化状态为锁定状态
    
    pthread_mutex_init(&mutex, &attr); // 初始化互斥锁;锁定状态的互斥锁
    

pthread_cond_t Bedingungsvariable

  • PTHREAD_COND_INITIALIZERBei der Initialisierung mit ist der Standardzustand , dass es aktiviert wurde . Diese Methode erstellt eine statisch initialisierte Bedingungsvariable, die für die Initialisierung statischer globaler Variablen oder statischer lokaler Variablen geeignet ist. wird im Beispielcode condmit initialisiert PTHREAD_COND_INITIALIZER, sodass es bei der Erstellung bereits aktiviert ist.

    pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
    
  • pthread_cond_initBei der Initialisierung mit der Funktion wird die Bedingungsvariable standardmäßig nicht aktiviert . Wenn Sie beim Erstellen aufwachen müssen, können Sie die Funktion pthread_cond_signaloder pthread_cond_broadcastvor der Initialisierung manuell aufrufen.

    pthread_cond_t cond;
    pthread_cond_init(&cond, NULL);
    

Bei der Verwendung von Mutexes und Bedingungsvariablen ist es wichtig, den korrekten Initialisierungsstatus sicherzustellen. Wenn es vor der Verwendung nicht initialisiert wird, kann es zu undefiniertem Verhalten oder Fehlern kommen. Daher wird empfohlen, Mutexe und Bedingungsvariablen vor der Verwendung immer explizit zu initialisieren.

Thread-Sicherheits-Produzenten-Verbraucher-Modell

Verwenden Sie Bedingungsvariablen + Mutex-Sperren, um den Effekt der zyklischen Ausführung von Produzenten- und Konsumenten-Threads zu erzielen.

#include<stdio.h>
#include<iostream>
#include<queue>
#include<unistd.h>
#include<pthread.h>

using namespace std;
int flags = 0;
pthread_cond_t cond;                  //条件变量
pthread_mutex_t mutex;              //互斥锁
//生产者
void *product_thread_start(void *arg)
{
    
    
    while (1)
    {
    
    
        /*flags:定义flags的目的就是为了确定生产者和消费者的执行的顺序
        原因是如果不定义这个flags,生产者和消费者都要抢占这个锁,不一定
        谁抢占成功,加上flags之后就能够确定生产者先执行

        为什么要 while (flags != 0)而不使用 if (flags != 0)
        如果生产者第一次抢占到锁,第二次还是生产者抢占到锁
        第二次执行pthread_cond_wait会立即退出,原因上一次它执行了pthread_cond_signal
        但是由于while是个循环flags的值没有改,锁它会第二次执行pthread_cond_wait休眠
        直到消费者线程执行一次*/
        pthread_mutex_lock(&mutex);
        while (flags != 0){
    
    
            cout<<"I am product: " << pthread_self()
                << "  flags == " << flags
                << "  LINE="<<__LINE__<<" [生产者等待]"<<endl;

            pthread_cond_wait(&cond, &mutex);           //flags == 1等待

            cout<<"I am product: " << pthread_self()
                << "  flags == " << flags
                << "  LINE="<<__LINE__<<" [开启生产]"<<endl;
        }

        flags = 1;
        sleep(1);
        printf("生产了一辆超级跑车\n");
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
        cout<<" [生产完]"<<endl;
        cout<<endl;
    }
    pthread_exit(NULL);
}

//消费者
void *consume_thread_start(void *arg)
{
    
    
    while (1)
    {
    
    
        pthread_mutex_lock(&mutex);
        while (flags == 0){
    
    
            cout<<"I am consume: " << pthread_self()
                << "  flags == " << flags
                << "  LINE="<<__LINE__<<"[消费者等待]"<<endl;

            pthread_cond_wait(&cond, &mutex);

            cout<<"I am consume: " << pthread_self()
                << "  flags == " << flags
                << "  LINE="<<__LINE__<<" [开启消费]"<<endl;
        }
        flags = 0;
        sleep(1);
        printf("我购买了一辆超级跑车\n");
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
        cout<<" [消费完]"<<endl;
        cout<<endl;
    }
    pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
    
    
    pthread_t product_tid, consume_tid;

    pthread_mutex_init(&mutex, NULL);       //默认状态是未锁定的(即解锁状态)
    pthread_cond_init(&cond, NULL);           //默认情况下条件变量是未被唤醒的

    if (pthread_create(&product_tid, NULL, product_thread_start, NULL))
        perror("create tid1 error");
    if (pthread_create(&consume_tid, NULL, consume_thread_start, NULL))
        perror("create tid1 error");

    pthread_join(product_tid, NULL);
    pthread_join(consume_tid, NULL);
    printf("product_tid=%#lx,consume_tid=%#lx\n", product_tid, consume_tid);
    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mutex);

    return 0;
}

Möglichkeit eins:

  • Der Verbraucher ergreift zum ersten Mal das Schloss und begibt sich in die Warteschleife;
  • Nachdem der Produzent nach „Beenden der Produktion“ aufwacht pthread_cond_signal(&cond);, greift der Produzent erneut auf die Sperre und geht in die Warteschleife.
  • Nachdem der Verbraucher nach dem „Beenden des Konsums“ aufgewacht ist pthread_cond_signal(&cond);, greift der Verbraucher erneut in die Sperre und tritt in die Warteschleife ein;

Fügen Sie hier eine Bildbeschreibung ein

Möglichkeit zwei:

  • Der Produzent greift zum ersten Mal in die Sperre und beginnt mit der Produktion;
  • Nachdem der Produzent nach „Beenden der Produktion“ aufwacht pthread_cond_signal(&cond);, greift der Produzent erneut auf die Sperre und geht in die Warteschleife.
  • Nachdem der Verbraucher nach dem „Beenden des Konsums“ aufgewacht ist pthread_cond_signal(&cond);, greift der Verbraucher erneut in die Sperre und tritt in die Warteschleife ein;

Fügen Sie hier eine Bildbeschreibung ein

Thread-sichere Warteschlange

Referenz

Referenz: Thread-sichere Warteschlangen

#include<stdio.h>
#include<iostream>
#include<queue>
#include<unistd.h>
#include<pthread.h>
using namespace std;
#define THREAD_COUNT 1              //生产者和消费者数量

//创建线程安全队列
class RingQueue{
    
    
public:
    RingQueue(){
    
    
        capacity = 1;
        pthread_mutex_init(&que_lock, NULL);
        pthread_cond_init(&consum_cond, NULL);
        pthread_cond_init(&product_cond, NULL);
    }
    ~RingQueue(){
    
    
        pthread_mutex_destroy(&que_lock);
        pthread_cond_destroy(&consum_cond);
        pthread_cond_destroy(&product_cond);
    }

    //往队列中放数据,生产
    void Push(int data){
    
    
        pthread_mutex_lock(&que_lock);
        while(que.size()>=capacity){
    
    
            cout<<"  que.size() == " << que.size()
               << " LINE="<<__LINE__<<" [生产者等待]"<<endl;

            pthread_cond_wait(&product_cond, &que_lock);

            /*为什么要用while循环呢?
        因为当生产者被唤醒后,需要再次判断队列是否可以满足生产的条件
        生产者或者消费者都是需要在等待结束后再次判断的*/
            cout<< "  que.size() == " << que.size()
                << "  LINE="<<__LINE__<<" [开启生产]"<<endl;
        }
        que.push(data);                           //生产,往队列中放入数据

        cout<<"I am product: " << pthread_self()
           << "I product number is " << data << endl;

        pthread_mutex_unlock(&que_lock);
        //生产者完成生产后唤醒消费者线程让消费者进行消费
        pthread_cond_signal(&consum_cond);
        cout<<endl;
    }

    //从队列中取数据,消费
    int Pop(){
    
    
        pthread_mutex_lock(&que_lock);
        while(que.size() <= 0){
    
    
            cout<< "  que.size() == " << que.size()
                << "  LINE="<<__LINE__<<" [消费者等待]"<<endl;

            pthread_cond_wait(&consum_cond, &que_lock);

            cout<< "  que.size() == " << que.size()
                << "  LINE="<<__LINE__<<" [开启消费]"<<endl;
        }
        int data = que.front();
        que.pop();

        cout<<"I am consume: " << pthread_self()
           << "I consume number is " << data << endl;

        pthread_mutex_unlock(&que_lock);
        //消费者线程消费之后通知生产者来生产
        pthread_cond_signal(&product_cond);

        cout<<endl;
        return data;
    }

private:
    queue<int> que;            //线程安全的队列
    //给队列一把锁,保证互斥,保证同一时刻只有一个线程对队列进行操作
    pthread_mutex_t que_lock;

    /*同步的条件变量,队列有元素,消息,没有元素等待,唤醒生产者
  保证生产者在队列中没有元素的时候进行生产(插入元素)*/
    pthread_cond_t consum_cond;
    pthread_cond_t product_cond;
    int capacity;               //队列容量,队列元素大于容量表示队满,不再往里插入元素
};

int g_val = 0;
//静态初始化保护g_val的互斥锁;默认状态是未锁定的(即解锁状态)
pthread_mutex_t g_val_lock = PTHREAD_MUTEX_INITIALIZER; //互斥锁

//生产者
void* product_thread_start(void* arg){
    
    
    RingQueue *q = (RingQueue*)arg;
    while(1){
    
    
        pthread_mutex_lock(&g_val_lock);//获取g_val的互斥锁
        q->Push(g_val);
        g_val++;
        sleep(1);
        pthread_mutex_unlock(&g_val_lock);
    }
}

//消费者
void* consum_thread_start(void* arg){
    
    
    RingQueue *q = (RingQueue*)arg;
    while(1){
    
    
        q->Pop();
    }
}

int main(){
    
    
    pthread_t consum_tid[THREAD_COUNT];
    pthread_t product_tid[THREAD_COUNT];
    RingQueue* q = new RingQueue();
    for(int i=0; i<THREAD_COUNT; ++i){
    
    
        int ret = pthread_create(&consum_tid[i], NULL, consum_thread_start, (void*)q);
        if(ret < 0){
    
    
            perror("pthread_create");
            return 0;
        }
        ret = pthread_create(&product_tid[i], NULL, product_thread_start, (void*)q);
        if(ret < 0){
    
    
            perror("pthread_create");
            return 0;
        }
    }
    for(int i=0; i<THREAD_COUNT; ++i){
    
    
        pthread_join(consum_tid[i], NULL);
        pthread_join(product_tid[i], NULL);
    }
    delete q;
    return 0;
}

Möglichkeit eins:

  • Der Produzent greift zum ersten Mal in die Sperre und beginnt mit der Produktion;
  • Nachdem der Verbraucher nach dem „Beenden des Konsums“ aufgewacht ist pthread_cond_signal(&product_cond);, greift der Verbraucher erneut in die Sperre und tritt in die Warteschleife ein;
    Fügen Sie hier eine Bildbeschreibung ein

Möglichkeit zwei:

  • Der Verbraucher ergreift zum ersten Mal das Schloss und begibt sich in die Warteschleife;
  • Nachdem der Verbraucher nach dem „Beenden des Konsums“ aufgewacht ist pthread_cond_signal(&product_cond);, greift der Verbraucher erneut in die Sperre und tritt in die Warteschleife ein;

Fügen Sie hier eine Bildbeschreibung ein

Thread-Mutex-API

  1. Variablen, die Mutex-Sperren definieren
pthread_mutex_t mutex;
  1. Thread-Mutex-Sperre initialisieren
int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t * attr); //动态初始化
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //静态初始化;未锁定的(即解锁状态)
功能:初始化线程的互斥锁
参数:
    @mutex:互斥锁变量的地址
    @attr:缺省属性,默认填写为NULL; 未锁定的(即解锁状态)
返回值:成功返回0,失败返回错误码
  1. Gesperrt
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex); 	//如果获取不到资源,不会阻塞,立即返回
功能:上锁(如果互斥锁可用直接能占用锁,如果互斥锁不可用将会阻塞等待)
参数:
    @mutex:互斥锁变量的地址
返回值:成功返回0,失败返回错误码
  1. Freischalten
int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:解锁
参数:
    @mutex:互斥锁变量的地址
返回值:成功返回0,失败返回错误码 
  1. Mutex-Sperre zerstören

    int pthread_mutex_destroy(pthread_mutex_t *mutex);
    功能:销毁互斥锁
    参数:
        @mutex:互斥锁变量的地址
    返回值:成功返回0,失败返回错误码
    

Thread-Synchronisation: API für Bedingungsvariablen

  1. Bedingungsvariablen definieren

    pthread_cond_t cond;
    
  2. Bedingungsvariablen initialisieren

    pthread_cond_t cond = PTHREAD_COND_INITIALIZER;			//静态初始化 //已经被唤醒的
    int pthread_cond_init(pthread_cond_t *restrict cond,  const pthread_condattr_t *restrict attr);
    功能:动态初始化一个条件变量
    参数:
       @cond	:	条件变量的指针
       @attr	:    	NULL使用默认属性  ;未被唤醒的
    返回值:成功返回0,失败返回非0
    
  3. Blockierende Wartebedingungsvariable

    int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
    功能:阻塞等待条件变量,在条件变量中维护了一个队列,
          这里的互斥锁就是为了解决在往队列中放线程的时候出现竞态问题的。
    参数:
        @cond	:条件变量的地址
        @mutex	:互斥锁
    返回值:成功返回0,失败返回非零
    

    Die Schritte für die Implementierung:
    1. Verwenden Sie pthread_mutex_lock zum Sperren.
    2. Rufen Sie pthread_cond_wait auf
    . 2.1 Stellen Sie den aktuellen Thread in die Warteschlange
    . 2.2 Entsperren. ---------- --------Threads, die dieselbe Sperre verwenden, können die Sperre
    2.3 Sleep erhalten --------------- ---- ---Warten
    2.4 Erlangen der Sperre
    2.5 Verlassen des Ruhezustands
    3. Der Thread führt mein Programm aus
    4. Verwenden Sie pthread_mutex_unlock zum Entsperren

  4. Senden Sie Signale oder Broadcasts an schlafende Threads

int pthread_cond_signal(pthread_cond_t *cond);
功能:唤醒一个休眠的线程
参数:
 	@cond:条件变量的地址
返回值:成功返回0,失败返回非零

int pthread_cond_broadcast(pthread_cond_t *cond);
功能:唤醒所有休眠的线程
参数:
 	@cond:条件变量的地址
返回值:成功返回0,失败返回非零  
  1. Bedingungsvariable zerstören
int pthread_cond_destroy(pthread_cond_t *cond);
功能:销毁条件变量
参数:
	 @cond:条件变量的地址
返回值:成功返回0,失败返回非零     
  1. Senden Sie Signale oder Broadcasts an schlafende Threads
int pthread_cond_signal(pthread_cond_t *cond);
功能:唤醒一个休眠的线程
参数:
 	@cond:条件变量的地址
返回值:成功返回0,失败返回非零

int pthread_cond_broadcast(pthread_cond_t *cond);
功能:唤醒所有休眠的线程
参数:
 	@cond:条件变量的地址
返回值:成功返回0,失败返回非零  
  1. Bedingungsvariable zerstören
int pthread_cond_destroy(pthread_cond_t *cond);
功能:销毁条件变量
参数:
	 @cond:条件变量的地址
返回值:成功返回0,失败返回非零     

Supongo que te gusta

Origin blog.csdn.net/qq_47355554/article/details/132679866
Recomendado
Clasificación