线程

线程

什么是线程?线程的优点是什么?
线程在Unix下,被称为轻量级的进程,线程虽然不是进程,但可以看作是Unix进程的表亲,同一进程中的多条线程共享该进程中的全部资源,如虚拟地址空间文件描述符、和信号处理等等,但同一进程中的多个线程有各自的调用栈(call satck),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。一个进程可以有很多线程,每条线程执行不同的任务。
线程可以提高应用程序在多核环境下处理诸如文件I/O或者socket I/O等会产生堵塞的情况的表现性能。在Unix系统中,一个进程包含很多东西,包括可执行的程序,以及一大堆诸如文件描述符地址空间等资源。在很多情况下,完成相关任务的不同代码间需要交换数据。如果采用多进程的方式,那么**通信就需要在用户空间和内核空间进程频繁的切换,开销很大,**但是如果使用多线程的方式,因为可以使用共享的全局变量,所以线程间的通信(数据交换)变得非常高效。
线程得创建,等待,退出

头文件:

#include<pthread.h>

函数

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);

int pthread_join(pthread_t thread, void **retval);

void pthread_exit(void *retval);

在多线程运行得环境中,如果多个线程都去访问和操作同一个地址或者变量,会造成出乎意料得结果,所以呢,线程之间就需要进行互斥和同步。有两种形式提供了线程之间得互斥和同步,锁和信号量,我们先看锁。

:顾名思义,就是把门加固,让任何人或者动物无法进入门内,也就是说当一个线程在对某个地址或者变量进行访问时,加一把锁,这个时候,其他得线程就不能访问该地址或变量了,只有等该线程把锁打开了,也就是释放了,其他线程申请到锁,才能继续访问。

//在主线程中初始化锁为解锁状态
pthread_mutex_t mutex;
pthread_mutex_init(&mutex,NULL);

//在编译时初始化锁为解锁状态:
 //锁初始化 
 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//访问对象时的加锁操作与解锁操作
//加锁:
pthread_mutex_lock(&mutex);
//释放锁 
pthread_mutex_unlock(&mutex);

下面看看一个简单得例子,使用多线程和互斥锁来模拟火车站窗口售票

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <semaphore.h>
#include<pthread.h>

#define N 32
pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
#define THREAD 5

typedef struct ticket
{
    int count;
    char saleticketname[N];
}TICKET;

typedef struct data
{
    TICKET *data;
    char threadname[N];
}THREADDATA;

void *saleticket(void *arg)
{
    THREADDATA *data = (THREADDATA *)arg;
    while(data->data->count>0)
    {
       pthread_mutex_lock(&g_mutex);
          printf("%s出售了,第%d张%s,",data->threadname,data->data->count--,data->data->saleticketname); 
        if(data->data->count>=0)
        {
            printf("出票成功,剩余%d张票\n",data->data->count);
            
        }
        else
        {
            printf("出票失败\n");
            exit(-1);
        }
           
        pthread_mutex_unlock(&g_mutex);
         sleep(1);
        
    }
    
    return NULL;
}

int main(void)
{
    int i=0;
    TICKET data;
    data.count=100;
    pthread_t tid1,tid2,tid3,tid4,tid5;
    THREADDATA thdata[THREAD];
    strcpy(data.saleticketname,"北京---邯郸");
//    pthread_mutex_init(&g_mutex,0);
 
    thdata[i].data=&data;
    memset(thdata[i].threadname,0,N);
    sprintf(thdata[i].threadname,"窗口%d",i);
    pthread_mutex_lock(&g_mutex);
    pthread_create(&tid1,NULL,saleticket,&thdata[i]);
    
    printf("%s开始出售%s车票\n",thdata[i].threadname,data.saleticketname);
    pthread_mutex_unlock(&g_mutex);
   
    i++;
    

    thdata[i].data=&data;
    memset(thdata[i].threadname,0,N);
    sprintf(thdata[i].threadname,"窗口%d",i);
    pthread_mutex_lock(&g_mutex);
    pthread_create(&tid2,NULL,saleticket,&thdata[i]);
    
    printf("%s开始出售%s车票\n",thdata[i].threadname,data.saleticketname);
    pthread_mutex_unlock(&g_mutex);
    
    i++;
    

    thdata[i].data=&data;
    memset(thdata[i].threadname,0,N);
    sprintf(thdata[i].threadname,"窗口%d",i);
    pthread_mutex_lock(&g_mutex);
    pthread_create(&tid3,NULL,saleticket,&thdata[i]);
    
    printf("%s开始出售%s车票\n",thdata[i].threadname,data.saleticketname);
   pthread_mutex_unlock(&g_mutex);
    
    i++;
   

    thdata[i].data=&data;
    memset(thdata[i].threadname,0,N);
    sprintf(thdata[i].threadname,"窗口%d",i);
    pthread_mutex_lock(&g_mutex);
    pthread_create(&tid4,NULL,saleticket,&thdata[i]);
    
    printf("%s开始出售%s车票\n",thdata[i].threadname,data.saleticketname);
    pthread_mutex_unlock(&g_mutex);
    
    i++;
    

    thdata[i].data=&data;
    memset(thdata[i].threadname,0,N);
    sprintf(thdata[i].threadname,"窗口%d",i);
    pthread_mutex_lock(&g_mutex);
    pthread_create(&tid5,NULL,saleticket,&thdata[i]);
    
    printf("%s开始出售%s车票\n",thdata[i].threadname,data.saleticketname);
    pthread_mutex_unlock(&g_mutex);
    
    pthread_join(tid5,NULL);
    pthread_join(tid4,NULL);
    pthread_join(tid3,NULL);
    pthread_join(tid2,NULL);
     pthread_join(tid1,NULL);

    system("pause");

    return 0;
}

看看执行结果
在这里插入图片描述
可以看到,窗口的顺序不是按顺序来执行的,这个是操作系统去调度的,但是没有出现重复售票的行为,这只是一个简单的例程,真正的火车票售票系统比这个复杂多了。

信号量

信号量本质上是一个非负数的整数计数器,也被用来控制对公共资源的访问。当公共资源增加的时候,调用信号量增加函数**sem_post()对其进行增加,当公共资源减少的时候,调用函数sem_wait()**来减少信号量。

头文件:

semaphore.h

信号量的数据结构为sem_t,本质上是一个long型整数.

函数:

//初始化信号量
int sem_init(sem_t *sem,int pshared,unsigned int value);
//成功返回0,失败返回-1
//参数:
//sem:指向信号量结构的一个指针
//pshared:不是0的时候,该信号量在线程间共享,否则只能为当前进程的所有线程门共享
//value:信号量的初始值
//信号量减一操作,当sem=0的时候该函数会堵塞
int sem_wait(sem_t *sem);
//成功返回0,失败返回-1
//参数
//sem:指向信号量的一个指针
//信号量的加一操作
int sem_post(sem_t *sem);
//成功返回0,失败返回-1
//参数
//sem:指向信号量的一个指针

下面就看一个简单的小例子,创建两个线程,一个线程负责接受终端的输入信息,另一个线程负责把从终端接收到的信息输出出来。

#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#include <semaphore.h>
#include<pthread.h>

sem_t g_sem1,g_sem2;
#define N 256
char g_buf[N];

void *driver(void *arg)
{
    while(1)
    {
        sem_wait(&g_sem1);
        printf("output--->%s\n",g_buf);
        sem_post(&g_sem2);
        if(strncmp(g_buf,"quit",4)==0)
        {
            break;
        }
    }
    return NULL;
}

void *sailer(void *arg)
{
    while(1)
    {
        sem_wait(&g_sem2);
        printf("please input-->\n");
        fgets(g_buf,N,stdin);
        sem_post(&g_sem1);
        if(strncmp(g_buf,"quit",4)==0)
        {
            break;
        }
    }
    return NULL;
}

int main(void)
{
    pthread_t tid1,tid2;
    int ret;
    sem_init(&g_sem1,0,0);
    sem_init(&g_sem2,0,1);

    ret=pthread_create(&tid1,NULL,driver,NULL);
    if(ret!=0)
    {
        printf("线程1创建失败\n");
        return -1;
    }

    ret=pthread_create(&tid2,NULL,sailer,NULL);
    if(ret!=0)
    {
        printf("线程2创建失败\n");
        return -1;
    }

    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值