《Unix/Linux编程实践教程》chapter14 线程机制:并发函数的使用

本文介绍了线程的概念及其在进程中的作用,强调了线程间的资源共享与通信可能导致的问题。通过示例展示了如何创建和管理线程,包括独立线程的使用。还讲解了互斥锁作为解决数据访问冲突的工具,并提到了线程间的条件变量通信。最后,讨论了线程管理对程序性能的影响以及系统调用如pthread_create和pthread_join的作用。
摘要由CSDN通过智能技术生成

chapter14 线程机制:并发函数的使用

章节知识总结

多个线程在一个单独的进程中运行,共享全局变量,因此线程间可以通过设置和读取这些全局变量来进行通信。线程的执行顺序是无法预测的。下面是一个多线程的例子:

#include<stdio.h>
#include<pthread.h>

#define NUM 5

void* print_msg(void*);

int main()
{
    pthread_t pid1,pid2;
    pthread_create(&pid1,NULL,print_msg,(void*)"hello ");
    pthread_create(&pid2,NULL,print_msg,(void*)"world\n");

    //等待线程pid1和pid2的结束
    pthread_join(pid1,NULL);
    pthread_join(pid2,NULL);

    return 0;
}

void* print_msg(void* msg)
{
    char* cp=(char*) msg;
    int i;
    for(i=0;i<NUM;++i){
        printf("%s",cp);
        fflush(stdout);
        sleep(1);
    }
    return;
}

在上面的程序中使用pthread_join函数来等待线程返回。每个线程都占用了系统资源。如果程序员忘记使用pthread_join来收回线程,这些线程所占用的资源就无法被回收。

可以创建一种不需要等待返回的线程,这种线程称为独立线程。当函数执行完毕之后,独立线程自动释放它所占用的所有的资源,它们自身甚至也不允许等待其他的线程返回。

创建一个独立线程的代码如下:

/* creating a detached thread */
pthread_t t;
pthread_attr_t attr_detached;
pthread_attr_init(&attr_detached);
pthread_attr_setdetached(&attr_detached,PTHREAD_CREATE_DETACHED);
pthread_create(&t,&attr_detached,func,arg);

独立线程可以用于web服务器中:每当服务器接收一个请求,则生成一个独立线程取去处理该请求,而主程序不需要等待独立线程的返回。

进程和线程有根本上的不同,每个进程都有其独立的数据空间、文件描述符以及进程的ID。而线程共享一个数据空间、文件描述符以及进程ID。

  • 共享数据空间:多线程中可以出现的一个问题是,一个线程分配了一块空间存储一个字符串,当此线程做其他事情的时候,另一个线程使用free释放这块空间。那么原先的线程中本来指向此空间的指针现在只想了一块已经被释放的地方。
  • 共享的文件描述符:在多进程中,执行fork语句之后,文件描述符自动被复制,从而子进程得到了一套新的文件描述符。而在多线程中,多个线程共享一套文件描述符。
  • fork、exec、exit、signals:如果一个线程执行了exit,那么整个进程都将结束运行。

由于线程共享数据空间,为了避免数据读取错乱,线程系统包含了称为互斥锁的变量,它可以使线程间很好的合作,避免对于变量、函数以及资源的访问冲突。

可以通过pthread_mutex_lockpthread_mutex_unlock分别来锁住和解除指定的互斥量,下面这个例子说明了互斥量在多线程中的使用:

#include<stdio.h>
#include<pthread.h>
#include<ctype.h>

#define oops(m) { perror(m); exit(1); }

void count_word(void*);

int count=0;
pthread_mutex_t counter_lock=PTHREAD_MUTEX_INITIALIZER;

int main(int ac,char* av[])
{
    if(ac!=3){
        fprintf(stderr,"usage: undefined parameters");
        exit(1);
    }
    pthread_t pid1,pid2;
    pthread_create(&pid1,NULL,count_word,(void*)av[1]);
    pthread_create(&pid2,NULL,count_word,(void*)av[2]);
    pthread_join(pid1,NULL);
    pthread_join(pid2,NULL);

    printf("Total:%d\n",count);

    return 0;
}

void count_word(void* f)
{
    char* filename=(char*) f;
    FILE* file;
    if((file=fopen(filename,"r"))!=NULL){
        int ch='\0',pre='\0';
        while((ch=getc(file))!=EOF)
        {
            //这个判断有问题!!!
            if(!isalnum(ch)&&isalnum(pre))
                pthread_mutex_lock(&counter_lock);
                ++count;
                pthread_mutex_unlock(&counter_lock);
            pre=ch;
        }
        fclose(file);
    }
    else{
        oops(filename);
    }
}

如果共享数据的访问次数频繁,使用互斥量会使得程序运行速度变慢。

线程之间通过pthread_cond_waitpthread_cond_signal来进行通信。pthread_cond_wait函数总是和互斥锁在一起使用。此函数先自动释放所指定的锁,然后等待条件变量的变化。如果在调用此函数之前,互斥量mutex并灭有被锁住,函数执行的结果是不确定的。

系统调用
pthread_create
用途创建一个新的线程
头文件#include<pthread.h>
函数原型int pthread_create(pthread_t* thread,pthread_attr_t* attr,void* (func)(void),void* arg);
参数thread: 指向pthread_t类型变量的指针;attr:指向pthread_attr_t类型变量的指针,或者为NULL; func:指向新线程所运行函数的指针;arg:传递给func的参数
返回值0: 成功返回 ; errcode:错误
pthread_join
用途等待某线程终止
头文件#include<pthread.h>
函数原型int pthread_join(pthread_t thread,void* *retval)
参数thread: 所等待的线程; retval:指向某存储线程返回值的变量
返回值0:成功返回;errcode:错误
  • pthread_mutex_lock():用来锁住指定的互斥量。
  • pthread_mutex_unlock():用来给指定的互斥量解锁。
  • pthread_cond_wait(pthread_cond_t* cond,pthread_mutex_t* mutex):使线程挂起直到另一个线程通过条件变量发出消息。
  • pthread_cond_signal(pthread_cond_t* cond):通过条件变量cond发送消息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值