C++之多线程编程互斥锁-四

C++之多线程编程互斥锁

在线程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为” 互斥锁” 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
可以保证以下三点:
1.原子性:把一个互斥量锁定为一个原子操作,这意味着操作系统(或pthread函数库)保证了如果一个线程锁定了一个互斥量,没有其他线程在同一时间可以成功锁定这个互斥量。

2.唯一性:如果一个线程锁定了一个互斥量,在它解除锁定之前,没有其他线程可以锁定这个互斥量。

3.非繁忙等待:如果一个线程已经锁定了一个互斥量,第二个线程又试图去锁定这个互斥量,则第二个线程将被挂起(不占用任何cpu资源),直到第一个线程解除对这个互斥量的锁定为止,第二个线程则被唤醒并继续执行,同时锁定这个互斥量。

从以上三点,我们看出可以用互斥量来保证对变量(关键的代码段)的排他性访问

创建C++控制台程序,代码如下

#include "stdafx.h"
#include <iostream>
#include <pthread.h> 
//多线程头文件,可移植众多平台, pthread头文件和库需要自己下载,
//下载地址    https://sourceware.org/pthreads-win32/#download
//进入下载网站找到相应的 .exe下载即可,各种版本均可
#define NUM_THREADS 5 //进程数

int sum = 0; //定义全局变量,让所有线程同时写,这样就需要锁机制
pthread_mutex_t sum_mutex; //互斥锁

using namespace std;
//互斥锁的实现 
class hhh
{
public:
    //如何在线程函数中传入参数
    static void * sayHello( void * args)
    {
        //对传入的参数进行强制类型转换,由无类型指针转变为整形指针,再用*读取其指向到内容
        std:: cout<< "hello  "<< *((int *)args) <<endl;
        //先加锁,在修改sum的值,锁被占用就阻塞,知道拿到锁在修改sum
        pthread_mutex_lock(&sum_mutex);
        std::cout<<"before sum is : "<<sum<< "  in thread" << *((int*)args) <<endl;
        sum += *((int *)args);
        std::cout<<"after sum is : "<< sum << "    in thread  " << *((int *)args) <<endl;
        //释放锁,供其他线程使用
        pthread_mutex_unlock(&sum_mutex);
        //线程退出时添加退出的信息,status供主程序提取线程的结束信息
        pthread_exit(0);
        return NULL;
    }
};

//线程创建时属性参数的设置 pthread_attr_t 及 join功能的使用
/*
线程的属性由结构体pthread_attr_t进行管理。
typedef struct
{
    int                           detachstate;     线程的分离状态
    int                          schedpolicy;   线程调度策略
    struct sched_param      schedparam;   线程的调度参数
    int inheritsched; 线程的继承性 
    int scope; 线程的作用域 
    size_t guardsize; 线程栈末尾的警戒缓冲区大小 
    int stackaddr_set; void * stackaddr; 线程栈的位置 
    size_t stacksize; 线程栈的大小
}pthread_attr_t;
*/

int _tmain(int argc, _TCHAR* argv[])
{
    pthread_t tids[NUM_THREADS]; //进程 id
    int indexex[NUM_THREADS]; //用来保存i的值避免被修改
    //线程属性结构体,创建线程时加入的参数
    pthread_attr_t attr; 
    pthread_attr_init(&attr); //初始化
    //设置想要指定线程属性参数,这个参数表明这个线程是可以join连接的
    //join 功能表示主程序可以等线程结束后再去做某事,实现了主程序和线程同步功能
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    //对锁进行初始化
    pthread_mutex_init(&sum_mutex, NULL);

    for (int i = 0; i < NUM_THREADS; i ++)
    {
        //参数1创建的线程id,参数2 线程参数,参数3 线程运行函数的地址,参数4函数的参数
        //传入的参数必须强制转换为 void * 类型,即无类型指针,取出 i 的地址 &i
        indexex[i] = i;
        int ret = pthread_create(&tids[i], &attr, hhh::sayHello, (void *)&(indexex[i]));

        if (ret != 0)//创建线程成功返回 0
        {
            std::cout<<"pthread_create  error:error_code"<<endl;
        }
    }
    //释放内存
    pthread_attr_destroy(&attr);
    void * status;
    for (int i = 0; i < NUM_THREADS;i ++)
    {
        //主线程join每个线程后取得每个线程的退出信息status
        int ret = pthread_join(tids[i], &status);
        if (ret != 0)
        {
            std::cout<< "pthread_join error =  "<<ret <<endl;
        }
    }

    std::cout<<"finally sum is "<<sum <<endl;
    //注销锁
    pthread_mutex_destroy(&sum_mutex);
    //等待各个线程退出后,进程才结束,否则进程强制结束,线程处于未终止的状态
    pthread_exit(NULL);

    return 0;
}

运行如下

这里写图片描述

再次运行

这里写图片描述

再次运行

这里写图片描述

//每次运行效果不一样
//可见sum的访问和修改顺序是正常的,这就达到了多线程的目的了,但是线程的运行顺序还是混乱的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值