深入浅出:C语言线程以及线程锁

简介: 线程锁的基本思想是,只有一个线程能持有锁,其他试图获取锁的线程将被阻塞,直到锁被释放。这样,锁就确保了在任何时刻,只有一个线程能够访问临界区(即需要保护的代码段或数据),从而保证了数据的完整性和一致性。线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。一个进程可以包含一个或多个线程,而每个线程都有自己的指令指针和寄存器状态,它们共享进程的资源,如内存空间、文件句柄和网络连接等。线程锁的概念

目录

线程和线程锁概念

线程锁的概念

线程的特点

线程的使用

创建线程 pthread_create

回收线程pthread_join

退出线程 pthread_exit

线程锁的使用

线程同步之互斥锁(Mutex)

初始化互斥锁

获取互斥锁

释放互斥锁

销毁互斥锁

初始化条件变量

等待条件变量

发送信号

广播信号

销毁条件变量

实例:每次打印都实现翻转数组


线程和线程锁概念

线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。一个进程可以包含一个或多个线程,而每个线程都有自己的指令指针和寄存器状态,它们共享进程的资源,如内存空间、文件句柄和网络连接等。

线程锁的概念

线程锁的基本思想是,只有一个线程能持有锁,其他试图获取锁的线程将被阻塞,直到锁被释放。这样,锁就确保了在任何时刻,只有一个线程能够访问临界区(即需要保护的代码段或数据),从而保证了数据的完整性和一致性。

线程的特点

  1. 轻量级进程:相比进程,线程的创建和切换成本更低,因为它们共享相同的地址空间和资源,不需要进行系统调用和上下文切换。
  2. 并发执行:线程允许在一个进程内部并发执行多个控制流,使得程序能够同时处理多个任务,提高程序的响应速度和效率。
  3. 资源共享:线程共享进程的资源,如内存、文件句柄和网络连接等,这减少了资源的开销,但也要求对共享资源进行同步和保护,以防止数据竞争和不一致。
  4. 通信便捷:由于线程共享同一进程的资源,它们之间的通信比进程间通信更为简单和快速,通常只需要使用局部变量或全局变量即可。
  5. 独立调度和执行:线程可以独立于其他线程进行调度和执行,操作系统可以根据需要将CPU时间分配给不同的线程,而无需切换到不同的进程。
  6. 线程状态:线程也有自己的生命周期,包括创建、就绪、运行、阻塞和终止等状态。线程状态的变化由操作系统调度器控制。
  7. 线程同步:为了保证数据的一致性和完整性,线程在访问共享资源时需要进行同步。常用的同步机制包括互斥锁(mutex)、信号量(semaphore)、条件变量(condition variable)等。
  8. 线程间通信:虽然线程共享资源,但在某些情况下,线程之间也需要进行通信,如通知某一线程完成特定任务或传递数据。这可以通过共享内存、信号量或条件变量等方式实现。
  9. 线程优先级:线程可以有不同的优先级,高优先级的线程在调度时会得到更多的CPU时间,从而影响线程的执行顺序和进程的整体性能。

线程的使用

创建线程 pthread_create

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, 
                    void *(*start_routine) (void *), void *arg);
功能:创建线程
参数:thread:线程标识
            attr:线程属性, NULL:代表设置默认属性
            start_routine:函数名:代表线程函数
            arg:用来给前面函数传参
返回值:成功:0
              失败:错误码

image.gif

回收线程pthread_join

int  pthread_join(pthread_t thread,  void **value_ptr) 
功能:用于等待一个指定的线程结束,阻塞函数
参数:thread:创建的线程对象
        value_ptr:指针*value_ptr指向线程返回的参数
返回值:成功 : 0
       失败:errno

image.gif

退出线程 pthread_exit

int  pthread_exit(void *value_ptr) 
功能:用于退出线程的执行
参数:value_ptr:线程退出时返回的值(任意类型)
返回值:成功 : 0
        失败:errno

image.gif

简单用线程实现一下主线程循环从终端输入,线程函数将数据循环输出,当输入quit结束程序。

image.gif 编辑

线程锁的使用

线程同步之互斥锁(Mutex)

互斥锁(Mutex)是一种用于同步线程访问共享资源的机制,确保在任何时刻只有一个线程能够访问临界区,从而避免了数据竞争和不一致性问题。以下是互斥锁相关函数的详细解析:

初始化互斥锁

C

1int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);

image.gif

  • 功能:初始化互斥锁。
  • 参数
  • mutex:指向要初始化的互斥锁的指针。
  • attr:指向互斥锁属性结构的指针,如果为NULL,则使用默认属性。
  • 返回值:成功返回0,失败返回非零值。

获取互斥锁

C

1int pthread_mutex_lock(pthread_mutex_t *mutex);

image.gif

  • 功能:尝试获取互斥锁,如果锁已经被另一个线程持有,当前线程将被阻塞,直到锁可用。
  • 参数
  • mutex:指向要获取的互斥锁的指针。
  • 返回值:成功返回0,失败返回非零值。

pthread_mutex_lockpthread_mutex_trylock的区别在于,pthread_mutex_lock是阻塞的,即如果锁被占用,调用线程会等待直至获取到锁;而pthread_mutex_trylock是非阻塞的,如果锁被占用,它会立即返回,不等待锁释放。

释放互斥锁

C

1int pthread_mutex_unlock(pthread_mutex_t *mutex);

image.gif

  • 功能:释放由当前线程持有的互斥锁。
  • 参数
  • mutex:指向要释放的互斥锁的指针。
  • 返回值:成功返回0,失败返回非零值。

销毁互斥锁

C

1int pthread_mutex_destroy(pthread_mutex_t *mutex);

image.gif

  • 功能:销毁互斥锁,通常在不再需要互斥锁时调用。
  • 参数
  • mutex:指向要销毁的互斥锁的指针。
  • 返回值:成功返回0,失败返回非零值。

初始化条件变量

C

1int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);

image.gif

  • 功能:初始化条件变量。
  • 参数
  • cond:指向要初始化的条件变量的指针。
  • attr:指向条件变量属性的指针,通常设为NULL以使用默认属性。
  • 返回值:成功返回0,失败返回非零值。

等待条件变量

C

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

image.gif

  • 功能:线程挂起等待,直到条件变量被信号唤醒。
  • 参数
  • cond:指向要等待的条件变量的指针。
  • mutex:与条件变量关联的互斥锁,必须在调用前锁定并在返回后再次锁定。
  • 返回值:成功返回0,失败返回非零值。
  • 注释:当没有条件产生时函数会阻塞,同时会自动解锁互斥锁;一旦条件产生或接收到信号,函数结束阻塞并重新锁定互斥锁。

发送信号

C

1int pthread_cond_signal(pthread_cond_t *cond);

image.gif

  • 功能:向条件变量发送信号,唤醒一个等待该条件变量的线程。
  • 参数
  • cond:指向条件变量的指针。
  • 返回值:成功返回0,失败返回非零值。
  • 注释:通常在条件满足后调用,以通知等待线程继续执行。

广播信号

C

1int pthread_cond_broadcast(pthread_cond_t *cond);

image.gif

  • 功能:向条件变量广播信号,唤醒所有等待该条件变量的线程。
  • 参数
  • cond:指向条件变量的指针。
  • 返回值:成功返回0,失败返回非零值。
  • 注释:与pthread_cond_signal类似,但唤醒所有等待线程,而非仅唤醒一个。

销毁条件变量

C

1int pthread_cond_destroy(pthread_cond_t *cond);

image.gif

  • 功能:销毁条件变量。
  • 参数
  • cond:指向要销毁的条件变量的指针。
  • 返回值:成功返回0,失败返回非零值。

实例:每次打印都实现翻转数组

. image.gif 编辑

image.gif 编辑

注:由于线程是随机执行的,所以此时我们不得不用上互斥锁,否则就会出现一些意外情况,这与我们使用标志位是一个道理,例如flag为true的时候p1执行,为flase的p2执行,但是线程锁的逻辑更加严谨和细致一些,功能也更多一些。

相关文章
|
2月前
|
安全 Java 编译器
线程安全问题和锁
本文详细介绍了线程的状态及其转换,包括新建、就绪、等待、超时等待、阻塞和终止状态,并通过示例说明了各状态的特点。接着,文章深入探讨了线程安全问题,分析了多线程环境下变量修改引发的数据异常,并通过使用 `synchronized` 关键字和 `volatile` 解决内存可见性问题。最后,文章讲解了锁的概念,包括同步代码块、同步方法以及 `Lock` 接口,并讨论了死锁现象及其产生的原因与解决方案。
80 10
线程安全问题和锁
|
2月前
|
安全 Java 调度
Java编程时多线程操作单核服务器可以不加锁吗?
Java编程时多线程操作单核服务器可以不加锁吗?
43 2
|
2月前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
1月前
|
运维 API 计算机视觉
深度解密协程锁、信号量以及线程锁的实现原理
深度解密协程锁、信号量以及线程锁的实现原理
32 1
|
1月前
|
Java 应用服务中间件 测试技术
Java21虚拟线程:我的锁去哪儿了?
【10月更文挑战第8天】
31 0
|
1月前
|
安全 调度 数据安全/隐私保护
iOS线程锁
iOS线程锁
26 0
|
1月前
|
Java API
【多线程】乐观/悲观锁、重量级/轻量级锁、挂起等待/自旋锁、公平/非公锁、可重入/不可重入锁、读写锁
【多线程】乐观/悲观锁、重量级/轻量级锁、挂起等待/自旋锁、公平/非公锁、可重入/不可重入锁、读写锁
28 0
|
1月前
|
安全 Java 程序员
【多线程-从零开始-肆】线程安全、加锁和死锁
【多线程-从零开始-肆】线程安全、加锁和死锁
43 0
|
1月前
|
安全 Linux
Linux线程(十一)线程互斥锁-条件变量详解
Linux线程(十一)线程互斥锁-条件变量详解
|
2月前
|
存储 算法 Java
关于python3的一些理解(装饰器、垃圾回收、进程线程协程、全局解释器锁等)
该文章深入探讨了Python3中的多个重要概念,包括装饰器的工作原理、垃圾回收机制、进程与线程的区别及全局解释器锁(GIL)的影响等,并提供了详细的解释与示例代码。
28 0

热门文章

最新文章