多线程编程总结

之前自己写过一个所谓的线程总结,那是刚学习的时候,想的只是怎么创建线程,后来剖析源码的时候发现了自己在这方面知识的匮乏,于是最近痛定思痛,再去去看了一遍多线程编程。


根据运行环境和调度者身份:
线程可以分为内核线程和用户线程。
内核线程由内核来调度,运行在内核空间
用户线程运行在用户空间由线程库来调度。


当进程的一个内核线程获得CPU使用权时,它就加载并运行一个用户线程。


内核线程相当于用户线程的"容器",一个线程可以拥有M个内核线程和N个用户线程,其中M<=N,并在每个系统中M,N的比值是固定的。


线程实现的三种模式
完全在用户空间实现
完全由内核调度       1:1
双层调度


LinuxThreads和NPTL都是1:1的方式实现的。
现代Linux上默认使用的线程库是NPTL。



#include <pthread.h>
创建一个线程的函数pthread_create:
int pthread_create(pthread_t *thread,const pthread_attr_t* attr,void*(*start_routine)(void*),void* arg);


thread:新线程的标识符,pthread_t是一个整型类型
attr:用于设置新线程的属性,传递NULL则是表示使用默认线程属性
statr_routine:指定新线程将运行的函数
arg:指定新线程的参数
pthread_create成功时返回0,失败时返回错误码。


线程的退出:
#include <pthread.h>
void pthread_exit(void* retval);


线程的回收:
pthread_jion,一个线程中所有的线程都可以调用此函数来回收其他线程(只要他是可回收的),也就是等待其他线程结束,这类似于回收进程的wait和waitpid系统调用。


#include <pthread.h>
int pthread_join(pthread_t thread,void** retval);
thread是目标线程的标识符
retval参数则是目标线程返回的退出信息,成功的话就返回0,失败就返回错误码。




#include <pthread.h>
int pthread_cancel(pthread_t thread);
有时候我们希望异常终止一个线程,也就是取消线程,可以用这个函数来实现。
thread就是目标线程的标识符,该函数成功时返回0,失败则返回错误码。


接收到取消请求的目标线程也可以决定允许被取消还是不允许。
#include <pthread.h>
int pthread_stecancelstate(int state,int* oldstate);//状态
int pthread_stecanceltype(int type,int* oldtype);//类型

14.3线程属性
这个太杂了我的书给的也只是说一下,并不能总结什么,用到的时候查(由于目前还是基础所以没怎么用到这个)



之前的内容我之前的博客也有,就不划重点了,还有就是关于互斥量和条件变量API的总结原先写了。。忘记保存了,所以就不加了。。。具体实现和使用可以直接参考我发上来的代码


POSIX信号量
多线程程序也必须考虑同步问题。
三种专门用于线程同步的机制:
POSIX信号量
互斥量
条件变量



常用的POSIX信号量函数
#include <semaphore.h>
int sem_init(sem_t* sem,int pshared,unsigned int value);
int sem_destroy(sem_t* sem);
int sem_wait(sem_t* sem);//相当于P操作
int sem_trywait(sem_t *sem);
int sem_post(sem_t* sem);//相当于V操作

sem指向被操作的信号量
sem_init函数用于初始化一个未命名的信号量
phared参数指定信号量的类型,如果他的值是0,就表示这个信号量是当前进程的局部信号量,否则该信号量就可以在多个进程之间共享。
value制定的是信号量的初始值(不可以初始化一个已经被初始化了的信号量)


sem_destroy函数用于销毁信号量,释放他占用的内核资源,不能销毁一个被其他线程等待的信号量。


sem_wait函数以原子操作的方式将信号量的值减一,如果信号量值1,那么sem_wait会被阻塞,直到这个信号量具有非0值。


sem_trywait与sem_wait相似,不过它始终立即返回,而不论被操作的信号量是否具有非0值。


sem_post函数以原子操作的方式将信号量加1,当信号量大于0,那么就调用sem_wait等待信号量的线程被唤醒。


他们成功都返回0,失败返回-1


互斥锁用于同步线程对共享数据的访问。


条件变量用于在线程之间同步共享数据的值,条件变量提供了一种线程间的通知机制,当某个共享数据达到某个值的时候唤醒等待这个共享数据的线程。


头文件不想分文档我就直接在头文件定义了

#include <semaphore.h>
#include <pthread.h>
//封装信号量的类
//创建并初始化信号量


//sem,POSIX信号量


int InitSem(sem_t *sem)
{


    if(sem_init(sem,0,0)!=0)
    {
        return -1;//失败就返回-1
    }
    return 1;//成功返回0
}


int DestroySem(sem_t *sem)
{
    if(sem_destroy(sem)!=0)
    {
         return -1;
    }//同上
    return 1;
}


int WaitSem(sem_t* sem)//等待,作用相当于PV操作的-1
{
    if( sem_wait(sem)!=0)
    {
         return -1;
    }
    return 1;
}




int PostSem(sem_t *sem)
{
     if(sem_post(sem)!=0)
     {
         return -1;
     }
     return 1;
}

//互斥锁
void InitMutex(pthread_mutex_t* mutex)//这个基本和上面一致,想要看是否成功
//就设置返回值0成功,非0失败,我就不写了
{
   pthread_mutex_init(mutex,NULL);
}


void DestroyMutex(pthread_mutex_t* mutex)
{
    pthread_mutex_destroy(mutex);


}


void LockMutex(pthread_mutex_t *mutex)
{
     pthread_mutex_lock(mutex);
}


void UnlockMutex(pthread_mutex_t* mutex)
{
 pthread_mutex_unlock(mutex);
}
条件变量


void InitCond(pthread_cond_t* cond)
{
pthread_cond_init(cond,NULL);
}//初始化一个条件变量


void DestroyCond(pthread_cond_t* cond)
{
pthread_cond_destroy(cond);
}


void BroadCond(pthread_cond_t* cond)
{
 pthread_cond_broadcast(cond);
}//唤醒所有等待目标条件变量的线程


void SignalCond(pthread_cond_t* cond)//用于唤醒一个等待目标条件变量的线程
//至于那个被唤醒则取决于线程的优先级和调度策略
{
 pthread_cond_signal(cond);
}


//等待目标条件变量,mutex函数保证条件变量的互斥锁来保证等待的原子性。
void WaitCond(pthread_cond_t* cond,pthread_mutex_t* mutex)
{
 pthread_mutex_lock(mutex);
 pthread_cond_wait(cond,mutex);//先解锁,返回再上锁
 pthread_mutex_unlock(mutex);
}



POSIX信号量和互斥锁的应用

#include <unistd.h>
//#include <pthread.h>
#include <stdio.h>
#include "lock.h"


//1 sem_t sem1,sem2;
pthread_mutex_t mutex1,mutex2;


void* fun1(void* arg)
{
    int i =0;
    for(i;i<5;++i)
    {


  //1  WaitSem(&sem1);//减去1
    LockMutex(&mutex1);
    printf("启动线程1\n");
    UnlockMutex(&mutex2);
   //1 PostSem(&sem2);
    }
    pthread_exit((void*)"thread1 exit\n");
}




void* fun2(void* arg)
{
    int i =0;
    for(i;i<5;++i)
    {
   //1 WaitSem(&sem2);//减去1
        LockMutex(&mutex2);
        printf("启动线程2\n");
        UnlockMutex(&mutex1);
   //1 PostSem(&sem1);
    }
      pthread_exit((void*)"thread2 exit\n");
}


int main(int argc,char* argv[])
{
    void* ret;
  //1  InitSem(&sem1);
  //1  InitSem(&sem2);//初始都是0
  //1  PostSem(&sem1);
  //1  PostSem(&sem2);//都变成1




    InitMutex(&mutex1);
    InitMutex(&mutex2);




    pthread_t tid1,tid2;
    pthread_create(&tid1,NULL,fun1,NULL);
    pthread_create(&tid2,NULL,fun2,NULL);


    pthread_join(tid1,&ret); //ret = "thread1 exit"
    pthread_join(tid2,&ret); //ret = "thread2 exit"
 //1   DestroySem(&sem1);
//1  DestroySem(&sem2);




    DestroyMutex(&mutex1);
    DestroyMutex(&mutex2);


    return 0;
}


条件变量的应用

#include <unistd.h>
//#include <pthread.h>
#include <stdio.h>
#include "lock.h"


//1 sem_t sem1,sem2;
pthread_mutex_t mutexcond;
pthread_cond_t cond;


void* fun1(void* arg)
{
    int i =0;
    for(i = 0;i<5;++i)
    {
         printf("条件改变\n");
         SignalCond(&cond);
         sleep(1);
    }




    pthread_exit((void*)"thread1 exit\n");
}




void* fun2(void* arg)
{
    int i =0;
    for(i;i<5;++i)
    {
         WaitCond(&cond,&mutexcond);
         printf("接收到了条件的改变\n");
    }


    pthread_exit((void*)"thread2 exit\n");
}


int main(int argc,char* argv[])
{
    void* ret;


    InitMutex(&mutexcond);
    InitCond(&cond);




    pthread_t tid1,tid2;
    pthread_create(&tid1,NULL,fun1,NULL);
    pthread_create(&tid2,NULL,fun2,NULL);


    pthread_join(tid1,&ret); //ret = "thread1 exit"
    pthread_join(tid2,&ret); //ret = "thread2 exit"
 //1   DestroySem(&sem1);
//1  DestroySem(&sem2);




    DestroyMutex(&mutexcond);
    DestroyCond(&cond);


    return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值