POSIX线程 | 信号量、互斥锁、条件变量

文章目录

        • 什么是线程
        • 线程的优缺点
        • 线程函数
          • pthread_create()
          • pthread_exit()
          • pthread_join()
        • 代码示例
          • 信号量
          • 互斥锁
          • 条件变量
        • 线程安全的字符串分割函数

什么是线程

线程其实就是进程内部的一条执行路径或控制序列。

一个进程在同一时刻只做一件事情。有了多个控制线程以后,在程序设计时可以把进程设计成在同一时刻能够做不止一件事,每个线程处理各自独立的任务。

线程的优缺点

优点

  • 通过为每种事件类型的处理分配单独的线程,能够简化处理异步时间的代码。
  • 多个线程可以自动共享相同的存储地址空间和文件描述符。
  • 对于数据库服务器来说,这个明显的多任务工作如果用多进程方式将很难做到高效的完成,因为各个不同的进程必须紧密合作才能加锁和数据一致性方面的要求,而如果用多线程完成的话明显要比多进程容易得多。
  • 一般而言,线程之间的切换需要操作系统所做的工作远远要比进程切换做的工作少,因此多个线程对资源的需求远远小于多个进程的需求。

缺点

  • 对多线程程序的调试远远要比单线程程序调试困难得多,因为线程之间的交互非常难于控制。
  • 编写多线程程序往往需要非常仔细的设计,在多线程程序中,因为时序上的细微偏差或无意造成的变量共享而引发错误的可能性是很大的。

线程函数

pthread_create()

定义如下:

 #include 
 int pthread_create(pthread_t * thread, pthread_attr_t * attr, 
 void * (*start_routine)(void *), void * arg);
  • thread是新线程的标识符,pthread*函数通过它来引用新线程。pthread_t是一个整形类型.
  • attr参数用于设置新线程的属性,给他传递NULL表示使用默认的线程属性。
  • start_routine和arg参数分别指定新线程将运行的函数及其参数。
  • pthread_create()成功时返回0;失败时返回错误码。
pthread_exit()

线程一旦被创建好,内核就可以调度内核线程来执行start_routine函数指针所指向的函数了,函数结束的时候调用pthread_exit(),以确保安全的退出。

 #include 
 void pthread_exit(void *retval);
  • pthread_exit()函数通过retval参数向线程回收者传递其退出信息。
  • 它执行完不会返回到调用者,而且永远不会失败。
pthread_join()

一个进程中的所有线程都可以调用pthread_join()函数来回收其他的线程,即就是等待其他的线程结束,这类似于回收进程的wait()系统调用。pthread_join()定义如下:

    #include 
    int pthread_join(pthread_t thread, void **thread_return);  
  • thread参数是目标线程的标识符,thread_return是目标线程返回的退出信息。
  • 这个函数会一直被阻塞着,一直到被回收的线程结束为止。
  • 成功时返回0,失败时返回错误码。

可能的错误码如下:

错误码 描述
EDEADLK 可能引起死锁,比如两个线程互相针对对方调用pthread_join(),或者对自身调用pthread_join()
EINVAL 目标线程是不可回收的,或者已经有线程在回收该目标线程
ESRCH 目标线程不存在

代码示例

a.c

#include
#include
#include
#include
#include
#include
void* thread_fun(void* arg)
{
    int i=0;
    for(;i<10;i++)
    {
        printf("fun run\n");
        sleep(1);
    }
    pthread_exit("fun over\n");
}

int main()
{
    pthread_t id;
    pthread_create(&id,NULL,thread_fun,NULL);	//开启线程
    
    int i=0;
    for(;i<5;i++)
    {
        printf("main run\n");
        sleep(1);
    }
    //pthread_exit(NULL);      

    char*s=NULL;
    pthread_join(id,(void**)&s);	//等待子线程
    printf("s=%s\n",s);

    printf("main over\n");

}

POSIX线程 | 信号量、互斥锁、条件变量_第1张图片

b.c

#include
#include
#include
#include
#include
#include

#define MAXID 5
void* thread_fun(void* arg)
{
    int index=(int)arg;
    int i=0;
    for(;i<4;i++)
    {
        printf("index=%d\n",index);
        sleep(1);
    }
}

int main()
{
    pthread_t id[MAXID];
    int i=0;
    for(;i<MAXID;i++)
    {
        pthread_create(&id[i],NULL,thread_fun,(void*)i);
    }
    for(i=0;i<MAXID;++i)
    {
        pthread_join(id[i],NULL);
    }
    exit(0);
}

POSIX线程 | 信号量、互斥锁、条件变量_第2张图片

使用信号量控制的线程函数

#include
#include
#include
#include
#include
#include
#include

#define MAXID 5
sem_t sem;
int g =0;

void* thread_fun(void* arg)
{
    int index=*((int*)arg);
    int i=0;
    for(;i<1000;i++)
    {
        sem_wait(&sem);
        printf("g=%d\n",++g);
        sem_post(&sem);
    }
}

int main()
{
    pthread_t id[MAXID];

    sem_init(&sem,0,1);
    int i=0;
    for(;i<MAXID;i++)
    {
        pthread_create(&id[i],NULL,thread_fun,(void*)&i);
    }
    for(i=0;i<MAXID;++i)
    {
        pthread_join(id[i],NULL);
    }

    sem_destroy(&sem);
    exit(0);
}

POSIX线程 | 信号量、互斥锁、条件变量_第3张图片

信号量

sem.c

#include
#include
#include
#include
#include
#include
#include

sem_t sem;
void* pthread_fun(void*arg)
{   
    int i=0;
    for(;i<5;i++)
    {
        sem_wait(&sem);//p
        write(1,"A",1);
        int n=rand()%3;
        sleep(n);
        write(1,"A",1);
        sem_post(&sem);//v
        sleep(n);
    }

}


int main()
{
    sem_init(&sem,0,1);
    pthread_t id;
    pthread_create(&id,NULL,pthread_fun,NULL);

    int i=0;
    for(;i<5;i++)
    {
        sem_wait(&sem);//p
        write(1,"B",1);
        int n=rand()%3;
        sleep(n);
        write(1,"B",1);
        sem_post(&sem);//v
        sleep(n);
    }
    pthread_join(id,NULL);
    sem_destroy(&sem);
    exit(0);

}

在这里插入图片描述

互斥锁

lock.c

#include
#include
#include
#include
#include
#include
#include

//sem_t sem;
pthread_mutex_t mutex;


void* pthread_fun(void*arg)
{   
    int i=0;
    for(;i<5;i++)
    {
        pthread_mutex_lock(&mutex);
        //sem_wait(&sem);//p
        write(1,"A",1);
        int n=rand()%3;
        sleep(n);
        write(1,"A",1);
        //sem_post(&sem);//v
        pthread_mutex_unlock(&mutex);
        sleep(n);
    }
}
int main()
{
    //sem_init(&sem,0,1);
    pthread_mutex_init(&mutex,NULL);
    pthread_t id;
    pthread_create(&id,NULL,pthread_fun,NULL);

    int i=0;
    for(;i<5;i++)
    {
        //sem_wait(&sem);//p
        pthread_mutex_lock(&mutex);//p
        write(1,"B",1);
        int n=rand()%3;
        sleep(n);
        write(1,"B",1);
        //sem_post(&sem);//v
        pthread_mutex_unlock(&mutex);//v
        sleep(n);
    }
    pthread_join(id,NULL);
    //sem_destroy(&sem);
    pthread_mutex_destroy(&mutex);
    exit(0);

}

在这里插入图片描述

条件变量

cond.c

#include
#include
#include
#include
#include
#include

pthread_mutex_t mutex;
pthread_cond_t cond;

void*fun1(void*arg)
{
    char*s=(char*)arg;
    while(1)
    {
        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&cond,&mutex);
        pthread_mutex_unlock(&mutex);

        printf("fun1:buff=%s\n",s);
        if(strncmp(s,"end",3)==0)
        {
            break;
        }
    }
}

void*fun2(void*arg)
{
    char*s=(char*)arg;
    while(1)
    {
        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&cond,&mutex);
        pthread_mutex_unlock(&mutex);

        printf("fun2:buff=%s\n",s);
        if(strncmp(s,"end",3)==0)
        {
            break;
        }
    }
}

int main()
{
    pthread_t id[2];
    char buff[128]={0};

    pthread_mutex_init(&mutex,NULL);
    pthread_cond_init(&cond,NULL);

    pthread_create(&id[0],NULL,fun1,(void*)buff);
    pthread_create(&id[1],NULL,fun2,(void*)buff);
    
    while(1)
    {
        fgets(buff,128,stdin);

        if(strncmp(buff,"end",3)==0)
        {
            //唤醒所有线程
            pthread_mutex_lock(&mutex);
            pthread_cond_broadcast(&cond);
            pthread_mutex_unlock(&mutex);
            break;
        }
        else
        {
            //唤醒一个线程
            pthread_mutex_lock(&mutex);
            pthread_cond_signal(&cond);
            pthread_mutex_unlock(&mutex);
        }       
    }

    pthread_join(id[0],NULL);
    pthread_join(id[1],NULL);
    
    exit(0);

}

POSIX线程 | 信号量、互斥锁、条件变量_第4张图片

线程安全的字符串分割函数

test.c

#include
#include
#include
#include
#include
#include
#include

#define MAXID 5

void* thread_fun(void* arg)
{
    char str[]={"a b c d e f g h i j k l "};
    char*s1=NULL;
    char*s=strtok_r(str," ",&s1);	//线程安全的字符串分割函数strtok_r()
    while(s!=NULL)
    {
        printf("s=%s\n",s);
        sleep(1);
        s=strtok_r(NULL," ",&s1);
    }
}

int main()
{
    pthread_t id;
    pthread_create(&id,NULL,thread_fun,NULL);
    char arr[]={"1 2 3 4 5 6 7 8 9 10"};
 
    char*p1=NULL;
    char*p=strtok_r(arr," ",&p1);

    while(p!=NULL)
    {
        printf("p=%s\n",p);
        sleep(1);
        p=strtok_r(NULL," ",&p1);
    }

    pthread_join(id,NULL);

    exit(0);
}

POSIX线程 | 信号量、互斥锁、条件变量_第5张图片

你可能感兴趣的:(网络编程,linux)