UNIX多线程编程(3) 线程同步

好了,这篇讲解多线程的同步问题。
互斥是同步的一种,linux下提供了多种方式来处理线程同步,最常用的是互斥量,条件变量和信号量。

本文首先使用互斥锁,信号量来实现同步版本,然后在深层次的分析下互斥锁和信号量的实现机制和原理。

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include <unistd.h>
#include <semaphore.h>
pthread_mutex_t mutex;
pthread_mutex_t mutex2;
sem_t sem;
long int g_nCount = 0;



void* mythread1(void*pPM)
{
//    usleep(10);
    long int nThreadNum = *(long *)pPM;
    sem_post(&sem);

    usleep(100);
    pthread_mutex_lock(&mutex2);
    g_nCount++;

        printf("线程编号为%d  全局资源值为%d\n", nThreadNum, g_nCount);
    pthread_mutex_unlock(&mutex2);
    return 0;
}

void* mythread(void*pPM)
{

    long int nThreadNum = (long )pPM;
    pthread_mutex_unlock(&mutex);


   usleep(100);
   pthread_mutex_lock(&mutex2);
   g_nCount++;

        printf("线程编号为%d  全局资源值为%d\n", nThreadNum, g_nCount);
   pthread_mutex_unlock(&mutex2);
    return 0;
}
int main()
{
    printf(" 子线程报数\n");
    const int THREAD_NUM =10;
    pthread_t id[THREAD_NUM] ;
    pthread_mutex_init(&mutex, NULL);
    sem_init (&sem, 0, 1);
    pthread_mutex_init(&mutex2, NULL);

    for (int i = 0; i < THREAD_NUM;  )
    {
        pthread_mutex_lock(&mutex);
        i++;
        pthread_create(&id[i-1], NULL, mythread, (void*)i);
    }

    for (int i = 0; i < THREAD_NUM; i++)
        pthread_join(id[i], NULL);
    printf("有%d个用户登录后记录结果是%d\n", THREAD_NUM, g_nCount);



    g_nCount = 0;
    for (int i = 0; i < THREAD_NUM; )
    {
        sem_wait (&sem);
        i++;
        pthread_create(&id[i-1], NULL, mythread1, (void*)&i);

  }

    for (int i = 0; i < THREAD_NUM; i++)
        pthread_join(id[i], NULL);
    printf("有%d个用户登录后记录结果是%d\n", THREAD_NUM, g_nCount);
    sem_destroy(&sem);
    pthread_mutex_destroy(&mutex);
    return 0;
}

下面是实验结果
这里 子线程报数
线程编号为3 全局资源值为1
线程编号为4 全局资源值为2
线程编号为1 全局资源值为3
线程编号为2 全局资源值为4
线程编号为5 全局资源值为5
线程编号为6 全局资源值为6
线程编号为7 全局资源值为7
线程编号为8 全局资源值为8
线程编号为9 全局资源值为9
线程编号为10 全局资源值为10
有10个用户登录后记录结果是10
线程编号为2 全局资源值为1
线程编号为1 全局资源值为2
线程编号为4 全局资源值为3
线程编号为3 全局资源值为4
线程编号为5 全局资源值为5
线程编号为6 全局资源值为6
线程编号为7 全局资源值为7
线程编号为8 全局资源值为8
线程编号为9 全局资源值为9
线程编号为10 全局资源值为10
有10个用户登录后记录结果是10
写代码片

可以看出来,各子线程已经可以互斥的访问与输出全局资源了,但主线程与子线程之间的同步还是有点问题。
至于问题等我有空的时候好好分析一番。

下面要讲的是条件变量了。

所需头文件include<pthread.h>
函数原型 int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr);
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);
int pthread_cond_destroy(pthread_cond_t *cond); int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
函数参数 cond:条件变量
mutex:互斥量
函数返回值


下面用条件变量来实现同步的例子。

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include <unistd.h>
#include <semaphore.h>
pthread_mutex_t mutex;
pthread_mutex_t mutex2;
pthread_cond_t cond;
long int g_nCount = 0;





void* mythread(void*pPM)
{
    pthread_mutex_lock(&mutex);
    long int nThreadNum = (long )pPM;
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);


   usleep(100);
   pthread_mutex_lock(&mutex2);
   g_nCount++;

   printf("线程编号为%d  全局资源值为%d\n", nThreadNum, g_nCount);
   pthread_mutex_unlock(&mutex2);
    return 0;
}
int main()
{
    printf(" 子线程报数\n");
    const int THREAD_NUM =10;
    pthread_t id[THREAD_NUM] ;
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);

    pthread_mutex_init(&mutex2, NULL);

    for (int i = 0; i < THREAD_NUM;  )
    {
        pthread_mutex_lock(&mutex);
        i++;
        pthread_create(&id[i-1], NULL, mythread, (void*)i);
        pthread_cond_wait(&cond,&mutex);
        pthread_mutex_unlock(&mutex);
    }

    for (int i = 0; i < THREAD_NUM; i++)
        pthread_join(id[i], NULL);
    printf("有%d个用户登录后记录结果是%d\n", THREAD_NUM, g_nCount);

    pthread_mutex_destroy(&mutex);
    pthread_mutex_destroy(&mutex2);
    pthread_cond_destroy(&cond);
    return 0;
}

实验结果如下:

 子线程报数
线程编号为1  全局资源值为1
线程编号为2  全局资源值为2
线程编号为7  全局资源值为3
线程编号为3  全局资源值为4
线程编号为4  全局资源值为5
线程编号为5  全局资源值为6
线程编号为6  全局资源值为7
线程编号为8  全局资源值为8
线程编号为9  全局资源值为9
线程编号为10  全局资源值为10
有10个用户登录后记录结果是10

条件变量为什么要和互斥锁结合一起?
互斥锁一个明显的缺点是它只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起配合使用。使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。一旦其他的某个线程改变了条件变量,他将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。这些线程将重新锁定互斥锁并重新测试条件是否满足。一般说来,条件变量被用来进行线程间的同步。
两个线程操作同一临界区时,通过互斥锁保护,若A线程已经加锁,B线程再加锁时候会被阻塞,直到A释放锁,B再获得锁运行,进程B必须不停的主动获得锁、检查条件、释放锁、再获得锁、再检查、再释放,一直到满足运行的条件的时候才可以(而此过程中其他线程一直在等待该线程的结束),这种方式是比较消耗系统的资源的。而条件变量同样是阻塞,还需要通知才能唤醒,线程被唤醒后,它将重新检查判断条件是否满足,如果还不满足,该线程就休眠了,应该仍阻塞在这里,等待条件满足后被唤醒,节省了线程不断运行浪费的资源。这个过程一般用while语句实现。当线程B发现被锁定的变量不满足条件时会自动的释放锁并把自身置于等待状态,让出CPU的控制权给其它线程。其它线程 此时就有机会去进行操作,当修改完成后再通知那些由于条件不满足而陷入等待状态的线程。这是一种通知模型的同步方式,大大的节省了CPU的计算资源,减少了线程之间的竞争,而且提高了线程之间的系统工作的效率。这种同步方式就是条件变量。
参考文献:
[1].http://blog.csdn.net/morewindows/article/details/7470936
[2].http://blog.csdn.net/sishuiliunian0710/article/details/9625407
[3].UNIX网络编程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
POSIX多线程编程是一种基于UNIX操作系统的多线程编程模型,也是一种符合POSIX线程标准的编程方式。POSIX多线程编程可以帮助开发者更好地利用系统资源,并提高程序的性能和可扩展性。 POSIX多线程编程涉及的主要内容包括线程的创建、同步和调度等。通过使用线程库提供的函数和数据结构,开发者可以方便地创建和管理多个线程。线程可以共享进程的资源,包括内存、文件描述符等,这样可以避免进程间的数据传输和同步开销,提高程序的效率。 在POSIX多线程编程中,开发者可以使用同步机制来确保线程之间的正确协同工作。例如,互斥锁可以用来保护共享资源的访问,条件变量可以用来进行线程间的通信和等待。同时,开发者还可以使用信号量来进行线程间的同步互斥操作。这些同步机制可以帮助开发者实现良好的线程互动,避免数据竞争和死锁等问题。 此外,POSIX多线程编程还提供了一些线程调度的接口,开发者可以通过调整线程的优先级和睡眠时间等参数来控制线程的执行顺序和时间片分配。这样可以更好地满足不同线程对系统资源的需求,提高程序的相应能力和性能。 综上所述,POSIX多线程编程是一种强大且灵活的编程模型,它能帮助开发者充分发挥多核处理器的计算能力,优化程序的并发性能。通过合理使用线程的创建、同步和调度等技术,开发者可以编写出更高效、更可靠的多线程应用程序。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值