多线程--前驱式关系

这篇博客介绍了如何在Linux环境下使用多线程实现前驱式关系,即两个线程按照特定顺序打印数字1到9。作者通过示例代码讲解了`pthread_create`、`pthread_join`、`pthread_exit`和条件变量等多线程编程关键函数的用法,强调了线程创建与执行顺序的不确定性,并展示了线程同步的重要性。

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

一段时间没玩linux了,突然发现手生了,但是感觉还在,就是卡卡的,虚拟机装linux的孩子伤不起!!

这个例子是用来捡起线程编程知识:

俩个线程按顺序打印1、2、3、4、5、--9.最终必然是第一个线程打印9.但是此次必须保证线程2在线程1后退出!

以下是代码:

#include "stdio.h"
#include "string.h"
#include "errno.h"
#include <pthread.h>

pthread_t tid1,tid2;

struct msg
{
 int flag;
 int count ;
 pthread_mutex_t lock;
 pthread_cond_t cond;
};

void init(struct msg *my_msg )
{

   my_msg->flag = 1;
   my_msg-> count = 1;
   pthread_mutex_init(&(my_msg->lock),NULL);
   pthread_cond_init(&(my_msg->cond),NULL);

}

void* thread1_fcn(void *my_msg )
{

    while(1)
    {
       printf("thread1 start!\n");
        pthread_mutex_lock(&((struct msg*)my_msg)->lock);
         printf("thread1 pthread_cond_wait!\n");
        while((((struct msg*)my_msg)->flag)!=1)
        {
            pthread_cond_wait(&((struct msg*)my_msg)->cond,&((struct msg*)my_msg)->lock);

        }
        printf("thread1:%d\n",((struct msg*)my_msg)->count);

         ((struct msg *)my_msg)->count ++;
        (((struct msg*)my_msg)->flag) = 2;
        pthread_mutex_unlock(&((struct msg*)my_msg)->lock);

       pthread_cond_signal(&((struct msg *)my_msg)->cond);
        printf("thread1 signal!\n");
         if(((struct msg *)my_msg)->count >= 9)
        {
          //pthread_cond_signal(&((struct msg *)my_msg)->cond);
        //   pthread_mutex_destroy(&((struct msg*)my_msg)->lock); //is not dynamic malloc
	    //   pthread_cond_destroy(&((struct msg*)my_msg)->cond);

	       printf("thread1 exit!\n");
           break;
        //   pthread_exit(NULL);
        }

    }
        return NULL;

}

// add thread 1 exit then thread2 exit
void* thread2_fcn(void *my_msg )
{

    while(1)
    {
          printf("thread2 start!\n");
        pthread_mutex_lock(&((struct msg*)my_msg)->lock);
        printf("thread2 pthread_cond_wait!\n");
        while((((struct msg*)my_msg)->flag)!=2)
        {
            pthread_cond_wait(&((struct msg*)my_msg)->cond,&((struct msg*)my_msg)->lock);

        }

        printf("thread2:%d\n",((struct msg*)my_msg)->count);
        ((struct msg *)my_msg)->count ++;
        (((struct msg*)my_msg)->flag) = 1;


         pthread_mutex_unlock(&((struct msg*)my_msg)->lock);

          pthread_cond_signal(&((struct msg *)my_msg)->cond);
              printf("thread2 signal!\n");
        if(((struct msg *)my_msg)->count >= 9)
        {
              int err =pthread_join(tid1,NULL);//block

              //printf("thread2 pthread_join:%d,%s!\n",err,strerror(err));
              printf("thread2 exit!\n");
	          break;
        }
    }
    return NULL;
}


int main()
{
    struct msg my_msg;
    init(&my_msg);

    pthread_create(&tid1,NULL,thread1_fcn,&my_msg);

    pthread_create(&tid2,NULL,thread2_fcn,&my_msg);

   // pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);

    return 0;
}


以下是结果:打印出了中间结果方便后续分析。




常用的函数和解析

#include <pthread.h> 头文件

int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(*func) (void *), void *arg);

pthread_t *tid:线程id的类型为pthread_t,通常为无符号整型,当调用pthread_create成功时,通过*tid指针返回。

const pthread_attr_t *attr:指定创建线程的属性,如线程优先级、初始栈大小、是否为守护进程等。可以使用NULL来使用默认值,通常情况下我们都是使用默认值。 

void *(*func) (void *):函数指针func,指定当新的线程创建之后,将执行的函数。

void *arg:线程将执行的函数的参数。如果想传递多个参数,请将它们封装在一个结构体中。

返回值:成功返回0,否则返回一个错误编码。

注:由于多线程的缘故,每个线程都有一个errno 。

打印只需含头文件#include <errno.h> 打印如:printf("%d,%s!\n",err,strerror(err)); //见代码注释

注:联系创建多个线程,不一定先创建的先运行,如此题结果可知,线程2反倒先运行。!

int pthread_join (pthread_t tid, void ** status);

用阻塞自己的方式等待某个线程退出,注意,对于一个线程,不能多次调用,否则返回错误,不成功!

pthread_t tid:要等待的线程ID 

void ** status:如果不为NULL,那么线程的返回值存储在status指向的空间中(这就是为什么status是二级指针的原因!这种才参数也称为“值-结果”参数)。


void pthread_exit (void *status);

//线程退出!

void *status:指针线程终止的返回值。



int  pthread_cond_wait(pthread_cond_t  *cond,pthread_mutex_t *mutex);

pthread_cond_wait() 用于阻塞当前线程,等待别的线程使用pthread_cond_signal()或pthread_cond_broadcast来唤醒它

首先进入wait状态,先unlock,解锁,这样别人才有机会,并把线程放入等待队列,当被唤醒时,重新加锁lock。


int pthread_cond_signal(pthread_cond_t * cond); //个人理解只是发送信号,有内核处理相应的动作,并不会阻塞当前线程,可以看上面结果!

使用pthread_cond_signal一般不会有“惊群现象”产生,他最多只给一个线程发信号。假如有多个线程正在阻塞等待着这个条件变量的话,那么是根据各等待线程优先级的高低确定哪个线程接收到信号开始继续执行。如果各线程优先级相同,则根据等待时间的长短来确定哪个线程获得信号。但无论如何一个pthread_cond_signal调用最多发信一次。
但是pthread_cond_signal在多处理器上可能同时唤醒多个线程,当你只能让一个线程处理某个任务时,其它被唤醒的线程就需要继续 wait,而且规范要求pthread_cond_signal至少唤醒一个pthread_cond_wait上的线程,其实有些实现为了简单在单处理器上也会唤醒多个线程.
另外,某些应用,如线程池,pthread_cond_broadcast唤醒全部线程,但我们通常只需要一部分线程去做执行任务,所以其它的线程需要继续wait.所以强烈推荐对pthread_cond_wait() 使用while循环来做条件判断
(此部分来自wiki)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值