项目3 多线程并发锁

本文介绍了C/C++中多线程并发编程的基本概念,包括如何使用pthread_create创建线程,以及自旋锁、互斥锁和原子操作的区别与应用。通过实例展示了如何使用自旋锁和互斥锁保护临界资源,并探讨了CAS(CompareandSwap)实现锁的原理。
摘要由CSDN通过智能技术生成

项目3 多线程并发锁

本专栏知识点是通过<零声教育>的系统学习,进行梳理总结写下文章,对c/c++linux课程感兴趣的读者,可以点击链接,详细查看详细的服务:链接

多线程并发介绍

多线程是为了 让程序更加速度,上面是多线程的流程

编译的时候

对于含有<pthread.h>的程序:

在编译的时候需要加上额外的参数-lpthread,因为该头文件在Linux默认Import Library中没有,需要使用库libpthread.a进行编译链接。

gcc -o lock lock.c -lpthread

实现原理

主函数中的 pthread_create 调用用于创建线程。它接受四个参数:第一个参数是要创建的线程的ID,使用 &threadid[i] 获取线程ID的地址;第二个参数为线程属性,这里设置为 NULL;第三个参数是线程回调函数,即 thread_callback;第四个参数是传递给线程回调函数的参数,这里传递了指向 count 变量的指针。


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

#define THREAD_COUNT 10


void *thread_callback(void *arg){
    int *pcount = (int *)arg; // 接收线程数
    int i = 0;
    while (i++< 100000){
        (*pcount)++;
        usleep(1);
    }

}

int main() {
    pthread_t threadid[THREAD_COUNT] = {0};
    int i = 0;
    int count=0;
    for (i = 0; i < THREAD_COUNT; i++) {
        pthread_create(&threadid[i],NULL, thread_callback,&count);
    }

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

count 是临界资源

锁区别

自旋锁和 互斥锁区别:
什么时候使用:
锁的内容少,可以用自旋锁
锁的内容比较多,用互斥锁 可以节省

自旋锁:
while(1) 等待结果, 释放之后再立即执行

互斥锁:
引起现成切换,不会循环,如果占用就让出现成等待

互斥锁

相当于把 代码川起来,运行完这个就锁死 ,下一个再来

void *thread_callback(void *arg){
    int *pcount = (int *)arg;
    int i = 0;
    while (i++< 100000){

#if 0

        (*pcount)++;
#else
        pthread_mutex_lock(&mutex);
        (*pcount)++;
        pthread_mutex_unlock(&mutex);

#endif
        usleep(1);

    }

}

自旋锁

spinlock
进程共用

pthread_spinlock_t spinlock; //声明 自旋锁

使用:
pthread_spin_lock(&spinlock);
(*pcount)++;
pthread_spin_unlock(&spinlock);

原子操作

最好的实现方式

多条指令 变成一条指令,单条cpu 指令实现

实现一个函数 调用

int inc(int *value,int add){
    int old;
    __asm__ volatile(
            "lock; xaddl %2, %1;"
            : "=a" (old)
            : "m" (*value),"a"(add)
            : "cc","memory"
            );
    return old;
}


汇编代码执行以下步骤:

lock; xaddl %2, %1; - 这条指令执行原子交换操作。它将add参数中的值加到*value指向的内存位置上,并将之前的值存储在old变量中。lock前缀确保该指令以原子方式执行。
内联汇编代码使用了多个输入输出操作数:

"=a" (old) - old是一个输出操作数,之前的值存储在eax寄存器中。
"m" (*value) - *value是一个输入输出操作数,表示由value指向的内存位置。
"a" (add) - add是一个输入操作数,其值加载到eax寄存器中。

cas 实现

和其他锁其实一样,都是先加锁 确定线程完事,对比状态,一段线程结束释放,进入下一个线程

#define LOCK_STATE_OK 0
#define LOCK_STATE_LOCKED 100、

//声明 cas 锁
atomic_int lock = ATOMIC_VAR_INIT(LOCK_STATE_OK);


void acquire_lock(){

    int expected = LOCK_STATE_OK;
    int desired = LOCK_STATE_LOCKED;

    int success = __sync_bool_compare_and_swap(&lock, expected, desired);
    while (!success) {
        // 获取锁失败时的自旋等待
        expected = LOCK_STATE_OK;
        success = __sync_bool_compare_and_swap(&lock, expected, desired);

    }


}
//释放锁
void release_lock() {
    //printf("Releasing lock...\n");
    lock = 0;
}


//使用的时候

void *thread_callback(void *arg){
    int *pcount = (int *)arg;
    int i = 0;
    while (i++< 100000){

        acquire_lock(pcount);
        (*pcount)++;
        release_lock();

    }

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值