Linux 多线程编程(Pthread 库)学习笔记 三

 线程的数据处理 之 互斥锁


互斥锁

互斥锁用来保证一段时间内只有一个线程在执行一段代码
pthread_mutex_lock声明开始用互斥锁上锁,此后的代码直至调用pthread_mutex_unlock为止,均被上锁,即同一时间只能被一个线程调用执行。当一个线程执行到pthread_mutex_lock处时,如果该锁此时被另一个线程使用,那此线程被阻塞,即程序将等待到另一个线程释放此互斥锁

 

a线程先锁定互斥锁1,b线程先锁定互斥锁2,这时就出现了死锁。此时我们可以使用函数 pthread_mutex_trylock,它是函数pthread_mutex_lock的非阻塞版本,当它发现死锁不可避免时,它会返回相应的信息,程序员可以针对死锁做出相应的处理。另外不同的互斥锁类型对死锁的处理不一样,但最主要的还是要程序员自己在程序设计注意这一点。

 

条件变量
互斥锁一个明显的缺点是它只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用。使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。一旦其它的某个线程改变了条件变量,它将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。这些线程将重新锁定互斥锁并重新测试条件是否满足。一般说来,条件变量被用来进行线程间的同步.

条件变量的结构为pthread_cond_t函数pthread_cond_init()被用来初始化一个条件变量。它的原型为:
extern int pthread_cond_init  __P ((pthread_cond_t *__cond,

                                                             __const pthread_condattr_t *__cond_attr));
其中cond是一个指向结构pthread_cond_t的指针,cond_attr是一个指向结构pthread_condattr_t的指针。

结构 pthread_condattr_t是条件变量的属性结构,和互斥锁一样我们可以用它来设置条件变量是进程内可用还是进程间可用,默认值是 PTHREAD_ PROCESS_PRIVATE,即此条件变量被同一进程内的各个线程使用。注意初始化条件变量只有未被使用时才能重新初始化或被释放。

释放一个条件变量的函数为pthread_cond_ destroy(pthread_cond_t cond)。 

函数pthread_cond_wait()使线程阻塞在一个条件变量上。它的函数原型为:
extern int pthread_cond_wait __P ((pthread_cond_t *__cond,
                                                                pthread_mutex_t *__mutex));
线程解开mutex指向的锁并被条件变量cond阻塞。线程可以被函数pthread_cond_signal和函数 pthread_cond_broadcast唤醒,但是要注意的是,条件变量只是起阻塞和唤醒线程的作用,具体的判断条件还需用户给出,例如一个变量是否为0等等,这一点我们从后面的例子中可以看到。线程被唤醒后,它将重新检查判断条件是否满足,如果还不满足,一般说来线程应该仍阻塞在这里,被等待被下一次唤醒。这个过程一般用while语句实现。

另一个用来阻塞线程的函数是pthread_cond_timedwait(),它的原型为:
extern int pthread_cond_timedwait __P ((pthread_cond_t *__cond,
                                                                          pthread_mutex_t *__mutex,

                                                                           __const struct timespec *__abstime));
它比函数pthread_cond_wait()多了一个时间参数,经历abstime段时间后,即使条件变量不满足,阻塞也被解除。

 

函数pthread_cond_signal()的原型为:
extern int pthread_cond_signal  __P ((pthread_cond_t *__cond));
它用来释放被阻塞在条件变量cond上的一个线程。多个线程阻塞在此条件变量上时,哪一个线程被唤醒是由线程的调度策略所决定的。要注意的是,必须用保护条件变量的互斥锁来保护这个函数,否则条件满足信号又可能在测试条件和调用pthread_cond_wait函数之间被发出,从而造成无限制的等待

 

下面是使用函数pthread_cond_wait()和函数pthread_cond_signal()的一个简单的例子。

 #include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
using namespace std;


pthread_mutex_t count_lock;
pthread_cond_t count_nonzero;
int counter =0;
int estatus=-1;

void * decrement_count(void * argv);
void * increment_count(void * argv);

int main(int argc, char *argv[])
{
 printf("counter:%d\n",counter);
 pthread_t thrd1,thrd2;
 int ret;
 ret = pthread_create(&thrd1,NULL,decrement_count,NULL);
 if(ret)
 {
  perror("de1:");
  return 1;
 }
 
 ret = pthread_create(&thrd2,NULL,increment_count,NULL);
 if(ret)
 {
  perror("in1:");
  return 1;
 }

 int count=0;
 while(count!=20)
 {
  printf("counter:%d\n",counter);
  sleep(1);
 count++;
 }
 return 0;
}

void * decrement_count (void * argv)
{
 pthread_mutex_lock(&count_lock);
 while(counter==0)
  pthread_cond_wait(&count_nonzero,&count_lock);
 counter--;
 pthread_mutex_unlock(&count_lock);
 return &estatus;
}

void * increment_count(void * argv)
{
 pthread_mutex_lock(&count_lock);
   if(counter==0)
    pthread_cond_signal(&count_nonzero);
 counter++;
 pthread_mutex_unlock(&count_lock);
   return &estatus;
}

 

开始时 counter 为0,
ret = pthread_create(&thrd1,NULL,decrement_count,NULL)处生成一个thrd1线程运行decrement_count(),此线程内函数运行流程为:
锁定 互斥锁 count_lock,如果counter为0,此线程被阻塞在 条件 变量count_nonzero上.同时释放互斥锁count_lock.

 

与此同时主程序还在运行,创建另一个线程thrd2运行 increment_count,此线程内的函数流程如下:
锁定 互斥锁 count_lock,如果counter为0,唤醒在 条件 变量count_nonzero上的线程即thrd1.但是由于有互斥锁count_lock,thrd1还是在等待.然后count++,释放互斥锁,.......thrd1由于互斥锁释放,重新判断counter是不是为0,如果为0再把线程阻塞在 条件 变量count_nonzero上,但这时counter已经为1了.所以线程继续运行.counter--释放互斥锁......
与此主程序间隔打印counter运行一段时间退出.


 

后记,在编译的时候加上 -lpthread

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Linux多线程编程是指在Linux操作系统中使用多个线程来同时执行不同的任务,以提高程序的运行效率和响应速度。Linux提供了丰富的多线程编程接口,其中最常用的就是POSIX线程(Pthread。 使用Pthread进行多线程编程的一般步骤如下: 1. 包含头文件pthread.h 2. 创建线程,使用pthread_create函数 3. 等待线程结束,使用pthread_join函数 4. 退出线程,使用pthread_exit函数 5. 销毁线程,使用pthread_cancel函数 下面是一个简单的例子,用于创建两个线程,分别输出“Hello”和“World”: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> void *print_hello(void *arg) { printf("Hello\n"); pthread_exit(NULL); } void *print_world(void *arg) { printf("World\n"); pthread_exit(NULL); } int main(int argc, char *argv[]) { pthread_t t1, t2; // 创建线程1 if (pthread_create(&t1, NULL, print_hello, NULL) != 0) { printf("Create thread 1 error!\n"); exit(1); } // 创建线程2 if (pthread_create(&t2, NULL, print_world, NULL) != 0) { printf("Create thread 2 error!\n"); exit(1); } // 等待线程1结束 if (pthread_join(t1, NULL) != 0) { printf("Join thread 1 error!\n"); exit(1); } // 等待线程2结束 if (pthread_join(t2, NULL) != 0) { printf("Join thread 2 error!\n"); exit(1); } return 0; } ``` 在上面的例子中,我们定义了两个函数print_hello和print_world,分别用于输出“Hello”和“World”。在主函数中,我们创建了两个线程t1和t2,分别执行print_hello和print_world函数。使用pthread_join函数等待两个线程结束,最后退出程序。 除了Pthread之外,Linux还提供了其他多线程编程接口,如OpenMP、OpenCL等。不同的接口适用于不同的场景,需要根据具体情况选择合适的接口。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

szwm1010

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值