c语言多线程相关基础知识

最近在学习C语言多线程的相关基础知识,特此记录。
课程连接
多线程课程

本文相关参考

https://subingwen.cn/linux/thread-sync/#4-2-%E8%AF%BB%E5%86%99%E9%94%81%E4%BD%BF%E7%94%A8

多线程创建相关函数

pthread_t id //创建线程🆔id 。
pthread_create(&id,null,func,arg4);
//创建一个多线程,
//第一个参数是ID,
//第二个参数是线程的属性,通常使用默认值 
//第三个参数是线程函数
//第四个参数是将传入线程函数的参数,(如果想要传入多个参数,可以传入一个类)
pthread_exit()//线程退出函数,可以返回数据通常与 pthread_join()组合使用
pthread_join(id,void * res) //阻塞函数,可以与 pthread_exit()配合传出线程数据,比如在子线程退出传出一个数据pthread_exit(test);join在回收线程资源时可以将数据接收

互斥锁相关函数

互斥锁的意义:多个线程是共享同一个资源空间的,当多个线程同时对共享的内存空间进行读写的操作时,我们可以通过互斥锁来保证数据的同步性。(此处应该有个图片说明)

互斥锁相关函数说明

# include<pthread.h>
pthread_mutex_t mutex;//互斥锁的ID
pthread_mutex_init(&mutex,NULL);//初始化互斥锁
pthread_mutex_destroy(&mutex);//销毁互斥锁
pthread_mutex_lock(&mutex);//上锁
pthread_mutex_unlock(&mutex);//解锁
//通常上锁与解锁之间的代码段称为临界区,临界区的代码段不宜过长,尽量减少代码粒度
//我们利用互斥锁可以保证数据的同步性,当一个线程在使用共享内存资源时,另一个线程如果抢占了CPU的资源片,遇到互斥锁会阻塞在外等待,只有互斥锁解锁之后该等待的线程才会运行。

互斥锁的例子

通过create传入函数,之后通过join回收资源传回数据

# include <iostream>
# include <string>
# include <pthread.h>
using namespace std;
class rui{
public:
int age;
string name;
string like;
void change (string name1,int age1,string like1)
{
name=name1;
age=age1;
like=like1;
}
rui(string name1,int age1,string like1)
{
    name=name1;
    age=age1;
    like=like1;
}
};

void* ChangeValue(void * read)
{
    cout << "son process" << endl;
    rui * test=(rui *) read;
    test->change("rui1",23,"rui");
    pthread_exit(test);
}

int main()
{
rui data("rui",23,"rui1");
pthread_t id;
pthread_create(&id,NULL,ChangeValue,&data);
void * res;
pthread_join(id,&res);
rui * result=(rui *) res;
cout << "name  " << result->name<< endl;
cout << "age  " << result->age<< endl;
cout << "like  " << result->like<< endl;

return 0;
}

造成死锁的几类情况

1)忘记写解锁函数

2)在两个锁之间有return 忘记解锁

3)重复加锁(调用其他函数时候其他函数中有上锁)

注意多少个共享资源的个数多少把锁,不要看现线程数量

读写锁相关函数说明

//首先我们需要明确读写锁是一个锁,同时如果是读锁可以允许多个线程同时进行读操作,但是对于写操作来说,读写锁与互斥锁没有什么区别,都是线性的
pthread_rwlock_t rwlock;//读写锁的id
pthread_rwlock_rdlock(&rwlock);//读锁上锁
pthread_rwlock_unlock(&rwlock);//解锁
pthread_rwlock_wrlock(&rwlock);//写锁上锁
pthread_rwlock_init(&rwlock,NULL);//初始化读写锁
pthread_rwlock_destroy(&rwlock);//销毁读写锁

条件变量函数

pthread_cond_t //被条件阻塞线程信息会被记录到这个变量中,以便解除阻塞时候使用
pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr) //第一个参数是线程ID,第二个参数是线程的属性,可以填写默认值
pthread_cond_destory(pthread_cond_t *cond);//销毁线程
pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);//线程阻塞函数,哪个线程调用这个函数,哪个线程就被阻塞
// 唤醒阻塞在条件变量上的线程, 至少有一个被解除阻塞
int pthread_cond_signal(pthread_cond_t *cond);
// 唤醒阻塞在条件变量上的线程, 被阻塞的线程全部解除阻塞
int pthread_cond_broadcast(pthread_cond_t *cond);


创建多个线程,其中前几个线程对共享变量加1,在设置一个监控变量,一旦超过100,则置0;具体例子如下,具体思想为add线程每加1,则进入等待状态,等待监控线程的释放,若该数<100则正常释放,若该数>100,置0。唤醒等待线程。

# include<pthread.h>
# include<iostream>
# include<unistd.h>
using namespace std;
pthread_mutex_t mutex;
pthread_cond_t cond;
int count=0;
void * add(void * argv)
{  
 while(1)
{  pthread_mutex_lock(&mutex);
    count++;
    cout << "count is " << count << endl;
    pthread_cond_wait(&cond,&mutex);
    pthread_mutex_unlock(&mutex);
}
}

void *min1(void *argv)
{
    while(1)
    {
        pthread_mutex_lock(&mutex);
        count--;
        cout<< "fuck !!!! " << endl;
        pthread_mutex_unlock(&mutex);
      
    }
}

void *monitor(void * monitor)
{
    while(1)
    {
    cout << "monitor" << endl;
    pthread_mutex_lock(&mutex);
    if(count <100)
    { 
        pthread_cond_signal(&cond);
    }
    else
    {
    cout << "count >= 100" << endl;
    count =0;
    pthread_cond_signal(&cond);
    }
    
    pthread_mutex_unlock(&mutex);

    }

}


int main()
{
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
pthread_t p1,p2,p3,p4;

//pthread_create(&p3,NULL,min1,NULL);
pthread_create(&p4,NULL,monitor,NULL);
pthread_create(&p1,NULL,add,NULL);
pthread_create(&p2,NULL,add,NULL);
pthread_join(p4,NULL);
pthread_join(p1,NULL);
pthread_join(p2,NULL);
//pthread_join(p3,NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}

信号量函数

//时刻了解老赵老王的开车实例,生产者和消费者的资源是不一样的,生产者的资源是将车开回到车位,资源是车位,消费者是将车开出来,资源是车
//
sem_t sem; //类似ID函数
int sem_init(sem_t *sem, int pshared, unsigned int value);//初始化函数,最后函数为资源数
int sem_destroy(sem_t *sem);//资源释放,线程销毁。
// 参数 sem 就是 sem_init() 的第一个参数  
// 函数被调用sem中的资源就会被消耗1个, 资源数-1
int sem_wait(sem_t *sem);
// 调用该函数给sem中的资源数+1
int sem_post(sem_t *sem);

// 查看信号量 sem 中的整形数的当前值, 这个值会被写入到sval指针对应的内存中
// sval是一个传出参数
int sem_getvalue(sem_t *sem, int *sval);

信号量函数举例

实现功能与上一个例子一样,只不过用信号量函数说明 除了注意头文件,还有一个值的注意的是生产者和消费者线程不可能同时阻塞,需要注意到这一点。

# include<pthread.h>
# include<iostream>
# include<unistd.h>
#include <semaphore.h>
using namespace std;
pthread_mutex_t mutex;
sem_t semp;
sem_t semc;
int count=0;
void * add(void * argv)
{  
 while(1)
{   sem_wait(&semp);
    pthread_mutex_lock(&mutex);
    count++;
    cout << "count is " << count << endl; 
    pthread_mutex_unlock(&mutex);
    sem_post(&semc);
}

}


void *monitor(void * monitor)
{
    while(1)
    {
        sem_wait(&semc);
   pthread_mutex_lock(&mutex);
   if(count>=100)
   {
       cout << "count >=100" << endl;
       count=0;
   }
   pthread_mutex_unlock(&mutex);
   sem_post(&semp);
    
    }
   


}


int main()
{
pthread_mutex_init(&mutex,NULL);
sem_init(&semp,0,3);
sem_init(&semc,0,0);
pthread_t p1,p2;
pthread_create(&p1,NULL,add,NULL);
pthread_create(&p2,NULL,monitor,NULL);
pthread_join(p1,NULL);
pthread_join(p2,NULL);


sem_destroy(&semp);
sem_destroy(&semc);
pthread_mutex_destroy(&mutex);

return 0;
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值