IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 条件变量和信号量 -> 正文阅读

[C++知识库]条件变量和信号量

1.pthread
./pthread &显示进程号
在这里插入图片描述

ps 查看进程号
ps -T 查看线程号

也可以进入进程的proc目录查看线程
在这里插入图片描述

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>

static char g_buf[1000];
static sem_t g_sem;
static void *my_thread_func (void *data)
{
        while (1)
        {
                //sleep(1);
                /* 等待通知 */
                //while (g_hasData == 0);
                sem_wait(&g_sem);

                /* 打印 */
                printf("recv: %s\n", g_buf);
        }

        return NULL;
}


int main(int argc, char **argv)
{
        pthread_t tid;
        int ret;

        sem_init(&g_sem, 0, 0);

        /* 1. 创建"接收线程" */
        ret = pthread_create(&tid, NULL, my_thread_func, NULL);
        if (ret)
        {
                printf("pthread_create err!\n");
                return -1;
        }


        /* 2. 主线程读取标准输入, 发给"接收线程" */
        while (1)
        {
                fgets(g_buf, 1000, stdin);

                /* 通知接收线程 */
                sem_post(&g_sem);
        }
        return 0;
}

通过上述例程可以发现,多次执行该函数其次序是无序的,线程之间的竞争无法控制,通过使用信号量来使得线程顺序为可控的。
为了解决上述对临界资源的竞争问题,pthread线程引出了互斥锁来解决临界资源访问。通过对临界资源加锁来保护资源只被单个线程操作,待操作结束后解锁,其余线程才可获得操作权。

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <semaphore.h>

char getbuf[128] = {0};
static sem_t g_sem;/* 定义信号量 */
pthread_mutex_t mutex;/* 定义互斥锁 */

static void *WorkProduct(void *data)
{
          pthread_mutex_lock(&mutex);



         strcpy(getbuf, "data");
           pthread_mutex_unlock(&mutex);
            sem_post(&g_sem);
              pthread_exit(NULL);/* 必须线程退出否则打印不出data */


}
static void *WorkConsume(void *data)
{

                sem_wait(&g_sem);
                printf("%s\n",getbuf);
                pthread_exit(NULL);/* 必须线程退出否则打印不出data */

}

int main(int argc, char **argv)
{
        pthread_t tid, dit;
        sem_init(&g_sem, 0, 0);
        pthread_mutex_init(&mutex, NULL);
        pthread_create(&tid, NULL, WorkProduct, NULL);
         pthread_create(&dit, NULL, WorkConsume, NULL);

         pthread_join(tid,NULL);
         pthread_join(dit,NULL);

         return 0;
}

线程的退出与回收
线程的退出情况有三种:第一种是进程结束,进程中所有的线程也会随之结束。第二种是通过函数pthread_exit来主动的退出线程。第三种被其他线程调用pthread_cancel来被动退出。
当线程结束后,主线程可以通过函数pthread_join/pthread_tryjoin_np来回收线程的资源,并且获得线程结束后需要返回的数据。

  1. 线程主动退出
    pthread_exit函数原型如下:
    线程主动退出
#include <pthread.h>
void pthread_exit(void *retval);

pthread_exit函数为线程退出函数,在退出时候可以传递一个void*类型的数据带给主线程,若选择不传出数据,可将参数填充为NULL。

  1. 线程被动退出
    pthread_cancel函数原型如下:
    线程被动退出,其他线程使用该函数让另一个线程退出
#include <pthread.h>
int pthread_cancel(pthread_t thread);

成功:返回0
该函数传入一个tid号,会强制退出该tid所指向的线程,若成功执行会返回0。

  1. 线程资源回收(阻塞方式)
    pthread_join函数原型如下:
    线程资源回收(阻塞)
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);

该函数为线程回收函数,默认状态为阻塞状态,直到成功回收线程后才返回。第一个参数为要回收线程的tid号,第二个参数为线程回收后接受线程传出的数据。

  1. 线程资源回收(非阻塞方式)
    pthread_tryjoin_np函数原型如下:
    线程资源回收(非阻塞)
#define _GNU_SOURCE            
#include <pthread.h>
int pthread_tryjoin_np(pthread_t thread, void **retval);

该函数为非阻塞模式回收函数,通过返回值判断是否回收掉线程,成功回收则返回。

条件变量
条件变量时一种同步机制,用来通知其他线程条件满足了。一般是用来通知对方共享数据的状态信息,因此条件变量时结合互斥量来使用的。
创建和销毁条件变量
函数原型如下:
#include <pthread.h>
// 初始化条件变量

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);//cond_attr

通常为NULL

// 销毁条件变量

int pthread_cond_destroy(pthread_cond_t *cond);

这些函数成功时都返回0
等待条件变量
函数原型如下:

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

这需要结合互斥量一起使用,示例代码如下:

pthread_mutex_lock(&g_tMutex);
pthread_cond_wait(&g_tConVar, &g_tMutex);  // 如果条件不满足则,会unlock g_tMutex
                                           // 条件满足后被唤醒,会lock g_tMutex

/* 操作临界资源 */

pthread_mutex_unlock(&g_tMutex);

通知条件变量
函数原型如下:

int pthread_cond_signal(pthread_cond_t *cond);

p

thread_cond_signal函数只会唤醒一个等待cond条件变量的线程,示例代码如下:
pthread_cond_signal(&g_tConVar);

条件变量模拟信号量

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/syscall.h>

#define BUFSIZE 128
char data[]="This is data";
char buf[BUFSIZE]= {0};
pthread_mutex_t mutex;//定义互斥锁
pthread_cond_t cond1;//定义条件变量
pthread_cond_t cond2;//定义条件变量


void *WorkProduct(void *arg)
{
  printf("This is product\n");
  while(1)
  {
    
    pthread_mutex_lock(&mutex);
    while(buf[0] != 0)  /* 如果有数据 */
    {
      pthread_cond_wait(&cond2,&mutex);//获得互斥量后判断条件是否成立,没有成立释放互斥量,一旦返回就表示条件成立并且就会获得互斥量
  }
    
    strncpy(buf,data,sizeof(data)); //生产数据
   

    pthread_cond_signal(&cond1);//通知消费者条件成立了
    pthread_mutex_unlock(&mutex);//释放锁
    sleep(1);
  }
  return NULL;
}

void *WorkConsume(void *arg)
{
   printf("This is consume\n");
  while(1)
  {
    pthread_mutex_lock(&mutex);
    while( 0== buf[0])
    {
      pthread_cond_wait(&cond1,&mutex);
    }

    memset(&buf[0],0,sizeof(buf));//消耗数据
    
    pthread_cond_signal(&cond2);//通知生产者条件成立了
    pthread_mutex_unlock(&mutex);//释放锁
    sleep(1);
  }
  return NULL;
}

int main()
{
     pthread_t cons,prod;
     pthread_mutex_init(&mutex,NULL);//互斥锁初始化
     pthread_cond_init(&cond1,NULL);//条件变量初始化
     pthread_cond_init(&cond2,NULL);//条件变量初始化
    
  

    pthread_create(&prod,NULL,WorkProduct,NULL);
    pthread_create(&cons,NULL,WorkConsume,NULL);

  
    pthread_join(cons,NULL);//线程等待
    pthread_join(prod,NULL);
  

    pthread_mutex_destroy(&mutex);//销毁互斥锁
    pthread_cond_destroy(&cond1);
    pthread_cond_destroy(&cond2);


     return 0;
     }
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-26 11:12:28  更:2022-02-26 11:13:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:29:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码