并发(锁)

源文件中导入pthread.h包

因为在Linux中pthread线程库是需要链接的所以在编译的时候需要加上-lpthread

总体输入格式如下

gcc Threads.c  -lpthread -o Threads

 初步实现多线程

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

#define  THREAD_COUNT 20

void *thread_callback(void *arg)
{
     int *count = (int *)arg;
     int i = 0;

     while (i++ <100000)
     {
       (*count) ++;
       usleep(1);  // 进程休眠1微秒
     }    
}

int main()
{
     pthread_t threadid[THREAD_COUNT]  = {0};  //定义线程数组 长度为宏定义的20 每个元素都是 pthread_t 类型的变量,{0}是初始化为0
     int i = 0;
     int count = 0;

     //创建10个线程
     for (i = 0 ;i< THREAD_COUNT;i++)
     {  
      //创建线程 并共用count参数
        pthread_create(&threadid[i],NULL,thread_callback,&count);
     }

     for(i = 0 ; i<100;i++) 
     { 
        printf("count: %d \n" , count);
        sleep(1);
     }
}

互斥锁  在大型临界区或者多核CPU情况下,建议使用互斥锁。

//创建互斥锁

pthread_metux_t  xxxx;

//初始化互斥锁

pthread_metux_init  (&xxxx,null);

在理想状态下 线程1 执行完在执行线程2

但事实上 在执行线程1的过程中(未执行完线程1的指令) 插入线程2的指令 导致程序同一个数重复执行

老师的图解

为什么要加互斥锁

 因为 count是一个线程共用的临界资源所以需要对其加锁 使得在线程1调用count的时候线程2无法调用 效果类似于sql的锁  在调用前加锁 调用完成后解锁

自旋锁 通常用于小型临界资源

//创建自旋锁

pthread_spinlock_t  xxxx;

//初始化互斥锁

pthread_spinlock_init  (&xxxx,PTHREAD_PROCESS_SHARED);

类似于while(1);   从A进程进入锁中 B进程进不去就会一直等待锁解锁 直到A进程执行完毕

获取自旋锁时,如果发现自旋锁已经被其他线程持有,则当前线程会一直处于忙等状态,直到自旋锁被释放为止。因为自旋锁不涉及内核态切换,所以相较于互斥锁而言,可以避免系统调用的开销,在保护小型临界区时效率更高。

原子操作 把线程1的多条操作合并成一条 就可以避免执行过程中 被B进程突进 从而不使用锁 

注:也就是单条cpu指令的实现   也是一种锁但是比互斥锁和自旋锁更好

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

#define  THREAD_COUNT 10

pthread_mutex_t mutex; //定义一把互斥锁
pthread_spinlock_t  spinlock; //定义一把自旋锁


//count自加操作 三条命令合并一条
int  inc(int *value, int add)
{
    int old;
    __asm__ volatile
    (
         "lock;xaddl %2,%1"       //xadd1 代表 2+1后将值赋值到1中  在此代码块中1代表value 2代表add
         :"=a"(old)               //a代表寄存器  m是内存   
         : "m" (*value), "a"(add)  //代表在寄存器中将内存中的value值进行相加操作
         : "cc", "memory"           //cc:用于记录上一条指令执行的结果信息; memory:通过访问内存地址来读取或写入数据        
    );
    return old;
}

void *thread_callback(void *arg)
{
    int *count = (int *)arg;
    int i = 0;

    while (i ++ < 100000)
   {
#if 0 
        (*count)++;  //此程序中最重要的一行
#elif 0  //为0屏蔽代码块 类似于大段注释
        pthread_mutex_lock(&mutex); //上锁
        (*count)++;
        pthread_mutex_unlock(&mutex); //下锁      
#elif 0
        pthread_spin_lock(&spinlock);
        (*count)++;
        pthread_spin_unlock(&spinlock);
#else 
        inc(count,1);
#endif
    usleep(1);  // 进程休眠1微秒  
    }
}

int main()
{
    pthread_t threadid[THREAD_COUNT] = { 0 };  //定义线程数组 长度为宏定义的10 每个元素都是 pthread_t 类型的变量,{0}是初始化为0

    pthread_mutex_init(&mutex ,NULL);  //对线程锁的初始化
    pthread_spin_init(&spinlock ,PTHREAD_PROCESS_SHARED);  //对线程锁的初始化  第二个参数是代表进程共用
    
    int i = 0;
    int count = 0;

    //创建10个线程
    for (i = 0; i < THREAD_COUNT; i++)
    {
        //创建线程 并共用count参数
        pthread_create(&threadid[i], NULL, thread_callback, &count);
    }

    for (i = 0; i < 100; i++)
    {
        printf("count: %d \n", count);
        sleep(1);
    }
}

课后了解 CAS技术

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值