多线程同步

1.linux使用多线程同步的方法

1)互斥锁:当线程A锁定了互斥变量时,线程B再去锁定时就会被挂起,直到A解锁。
注意:当线程要不断的去轮询检查某个条件以判断是否可以操作需同步的数据时,可使用条件变量提高效率。
demo如下:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
​
pthread_mutex_t mutex;void *print_msg(void *arg)
{
    int i = 0;
    pthread_mutex_lock(&mutex); //互斥锁加锁
    for (i = 0; i < 20; i++)
    {
        printf(" i = %d\n", i);
        usleep(200);
    }
    pthread_mutex_unlock(&mutex);}int main()
{
    pthread_t id1, id2;
    pthread_mutex_init(&mutex, NULL);
    pthread_create(&id1, NULL, print_msg, NULL);
    pthread_create(&id2, NULL, print_msg, NULL);
    pthread_join(id1, NULL); //使主线程等待该线程结束后才结束,否则主线程很快结束,该线程没有机会执行
    pthread_join(id2, NULL);
    pthread_mutex_destroy(&mutex);return 0;
}

2)信号量:实际是一个整数,只要信号量的value大于0,其他线程就可以sem_wait成功,成功后信号量的value减1。若value值不大于0,则sem_wait使得线程阻塞,直到sem_post释放后value值加1,但是sem_wait返回之前还是会将此value值减1。
demo如下:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
#include <stdlib.h>void *thread_func(void* msg);
sem_t sem;
sem_t sem_add;#define MSG_SIZE 512int main()
{
    int res = -1;
    pthread_t thread;
    void *thread_result = NULL;
    char msg[MSG_SIZE];
​
    res = sem_init(&sem, 0, 0);
    if (res == -1)
    {
        printf("sem init failed\n");
        exit(-1);
    }
​
    res = sem_init(&sem_add, 0, 1);
    if (res == -1)
    {
        printf("sem_add init failed\n");
        exit(-1);
    }
​
    res = pthread_create(&thread, NULL, thread_func, msg);
    if (res != 0)
    {
        printf("pthread_create failed\n");
        exit(-1);
    }
    printf("input some text. Enter 'end' to finish...\n");
    
    sem_wait(&sem_add);
    while(strcmp("end\n", msg) != 0)
    {
        if (strncmp(msg, "TEST", 4) == 0)
        {
            strcpy(msg, "copy_data\n");
            sem_post(&sem);
            sem_wait(&sem_add);
        }
        fgets(msg, MSG_SIZE, stdin);
        sem_post(&sem); //sem信号量加1,让子线程开始执行
        sem_wait(&sem_add); //sem_add信号量减1,等待子线程处理完成}printf("waiting for thread to finish...\n");
    res = pthread_join(thread, &thread_result);
    if (res != 0)
    {
        printf("pthread_join faild\n");
        exit(-1);
    }printf("thread joined\n");sem_destroy(&sem);
    sem_destroy(&sem_add);
    exit(0);return 0;
}void* thread_func(void* msg)
{
    char *ptr = (char*)msg;
    sem_wait(&sem);
    while(strcmp("end\n", ptr) != 0)
    {
        int i = 0;
        for (; ptr[i] != '\0'; ++i )
        {
            if (ptr[i] >= 'a' && ptr[i] <= 'z')
            {
                ptr[i] -= 'a' - 'A';
            }
        }
        printf("you input %d characters\n", i - 1);
        printf("to uppercase: %s\n", ptr);sem_post(&sem_add);
        sem_wait(&sem);
    }
    sem_post(&sem_add);
    pthread_exit(NULL);
}

3)条件变量:经常和互斥锁一起使用,使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程会解开相应的互斥锁并等待条件发生变化,一旦其他的某个线程改变了条件变量,它将通知相应的条件变量唤醒一个或多个正被此变量阻塞的线程,这些线程将重新锁定互斥锁并重新测试条件是否满足。
       pthread_cont_init()
       pthread_cont_destroy()
       pthread_cont_wait() //线程解开mutex指向的锁并被条件变量阻塞
       pthread_cont_timedwait() //多了时间参数,当时间过了以后,即使条件变量不满足,阻塞也被解除
       pthread_cont_signal()/pthread_cont_broadcast //唤醒被条件变量阻塞的线程。
demo如下:

 pthread1()
 {
  pthread_mutex_lock(lock_s);
  sum++;
  pthread_mutex_unlock(lock_s);
  if (sum >= 100)
  {
   pthread_cond_signal(&cond_sum_ready);//先发送一次
  }
 }
 pthread2()
 {
  pthread_mutex_lock(lock_s);
  while(sum < 100)
  {
   pthread_cond_wait(&cond_sum_ready, &lock_s);//会先执行pthread_MUTEX_UNLOCK进行解锁,然后休眠
  }
  sum = 0;
  pthread_mutex_unlock(lock_s);
 }

注意:最终哪个线程接收到信号,根据优先级来

4)读写锁:可以多个线程同时占用读模式的读写锁,但是只能一个线程占用写模式的读写锁。

  • 当读写锁是写加锁状态时,在这个锁被解锁前,所有试图对这个锁加锁的线程都会被阻塞;
  • 当读写锁是读加锁状态时,其他线程可以读模式得到访问权,但是以写模式对它进行加锁的线程都将被阻塞;
  • 当读写锁是在读模式加锁状态时,如果有其他线程试图以写模式加锁,读写锁通常会阻塞随后的读模式锁请求,避免读模式锁长期占用,而写模式所长期阻塞;
    读写锁适用于对数据读的次数比写的次数多的情况。
           API接口:
           初始化和销毁:
           int pthread_rwlock_init();
           int pthread rwlock_destroy();
           读加锁、写加锁、解锁:
           pthread_rwlock_rdlock();
           pthread_rwlock_wrlock();
           pthread_rwlock_unlock();
           非阻塞获得读锁和写锁:
           pthread_rwlock_tryrdlock();
           pthread_rwlock_trywrlock();
    demo如下
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>#define Read_Num 2
​
pthread_rwlock_t lock;
​
class Data
{
    public:
        Data(int i, float f): I(i), F(f){}
        int GetI()
        {
            return I;
        }float GetF()
        {
            return F;
        }
​
    private:
        int I;
        float F;
};
​
Data *pData = NULL;void *read(void *arg)
{
    int *id = (int*)arg;
    while(true)
    {
        pthread_rwlock_rdlock(&lock);
        printf(" reader %d is reading data\n", *id);
        if (pData == NULL)
        {
            printf("data is NULL\n");
        }
        else
        {
            printf("data: I = %d, F = %f\n", pData->GetI(), pData->GetF());
        }
        pthread_rwlock_unlock(&lock);
    }
    pthread_exit(0);
}void *write(void *arg)
{
    while(true)
    {
        pthread_rwlock_wrlock(&lock); //写锁加锁后,解锁前,所有试图对该锁加锁的线程都会被堵塞
        printf("writer is wiriting data:\n");
        if (pData == NULL)
        {
            pData = new Data(2, 2.2);
            printf("writer is writing data: %d, %f\n", pData->GetI(), pData->GetF());
        }
        else
        {
            delete pData;
            pData = NULL;
            printf("wirter free the data\n");
        }
        pthread_rwlock_unlock(&lock);}
    pthread_exit(0);
}int main()
{
    pthread_t reader[Read_Num];
    pthread_t writer;
    for (int i = 0; i < Read_Num; i++)
    {
        pthread_create(&reader[i], NULL, read, (void*)&i);
    }
    pthread_create(&writer, NULL, write, NULL);
    while(1)
    {
        sleep(1);
    }
    return 0;
}

2.信号量和互斥锁之间的区别:

互斥锁用于互斥,对资源的访问是无序的,信号量用于同步,对资源的访问是有序的
 互斥量的加锁和解锁必须由同一线程对应使用,而信号量可以由一个线程释放,另一个线程得到

3.什么情况下会产生死锁以及怎样避免死锁

比如线程A,对资源M加锁,去申请资源N;
线程B,对资源N加锁,去申请资源M;
此种情况下会产生死锁,要有效的避免死锁,可使用银行家算法:
线程A和B在使用资源的时候按照同一顺序,即加锁时按照同一顺序,这样就可以避免死锁。

利用 TensorFlow 训练自己的目标识别器。本文内容来自于我的毕业设计,基于 TensorFlow 1.15.0,其他 TensorFlow 版本运行可能存在问题。.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

cpp加油站

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

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

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

打赏作者

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

抵扣说明:

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

余额充值