C语言学习:关于线程

留校第三周的任务,是线程控制,和网络编程的学习,为下周聊天室的编写打基础。本篇博客是基于《Linux C 编程实战》第八章和网络资料的,我对线程的理解。

线程(thread)是计算机中 独立运行 的最小单位,也可以看做是操作系统分配CPU时间的基本单位。
多线程 是一种很“节约”的结构,速度快、空间小、常被用来改善多命令大程序。

线程的创建

pthread_create函数
我们可以使用pthread_once函数,确保某函数只被执行一次。譬如书例8-2:

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

pthread_once_t once = PTHREAD_ONCE_INIT; 
void run(void){
    printf("Function run is running in thread %u\n",pthread_self());
}

void * thread1(void *arg){
    pthread_t thid = pthread_self();
    printf("Current thread's ID is %u\n", thid);
    pthread_once(&once,run);
    printf("thread1 ends\n");
}

void *thread2(void *arg){
    pthread_t thid = pthread_self();
    printf("CUrrend thread's ID is %u\n", thid);
    pthread_once(&once,run);
    printf("pthread2 ends\n");
}

int main(){
    pthread_t thid1,thid2;

    pthread_create(&thid1,NULL,thread1,NULL);
    pthread_create(&thid2,NULL,thread2,NULL);
    sleep(3);
    printf("main thread exit! \n");
    exit(0);
}

中,多个线程通过pthread_create调用同一个函数的情况下,该函数只在第一次时被执行。

线程的终止

线程有两种退出方式:

通过return自然返回主线程如果被返回或用exit退出,整个进程中的所有线程也会终止。
调用pthread_exit()退出仅有主线程消亡,进程等待所有线程结束。

值得注意的是:

  • 临界资源只能同时被 一个 线程持有,使用完毕后要及时释放,以免形成死锁。函数pthread_cleanup_push()pthread_cleanup_pop()就被用来清理所占资源。由于是以宏形式定义,且分别带有{ ,},所以必须出现在同一代码段中。

死锁:
  死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。一般由对共享资源的竞争引起。
发生条件:
  互斥、等待/持有、非抢占、形成等待环
在“哲学家问题”中,每人手握一只筷子,互相等待,即是线程死锁问题。

线程独立运行互不影响,终止时也不会产生通知,所以我们需要用pthread_join()等待线程的结束。当一个线程调用该函数后将会被挂起,等待参数线程终止后方可继续运行。一个线程不能被 多个线程如此等待,且需要处于 可 join 状态,否则无法被同步。

私有数据

  由于线程特殊的 共享数据空间 设计,当我们需要使用线程内部的变量时,需要创建线程的私有数据,它对于其他线程是屏蔽的。
  私有数据有操作函数pthread_key_createpthread_key_deletepthread_setspecificpthread_getspecific,以创建、删除键,并设置、读取数据。
其中,键(key)其实是一个不同线程都可以调用的变量,它们可以向key中填入不同的值。这个功能依靠数据结构数组TSD池实现。每创建一个私有数据,都将在结构数组中将某项设置为in_use并将索引返回给*key

线程的同步

由于共享资源,线程间的同步成为了一个重难点。我们可用互斥锁条件变量异步信号控制线程同步。

  • 互斥锁
    互斥锁只有两种状态:上锁和解锁。在同一时刻只能有一个线程掌握某个互斥锁,拥有上锁状态的线程能够对共享资源进行操作。若其他线程希望使用一个已上锁的互斥锁,则该线程会被挂起,等待互斥锁被解锁。
    当一个互斥锁使用完毕后,需要清除其占用的资源。(Linux内,互斥锁并不占用内存)
    周六的线程测验中,“哲学家问题”就运用了互斥锁,防止线程死锁。
 		usleep(10);//思考十秒
        pthread_mutex_lock(&chopstick[left]);//锁住左边筷子
        printf("Philosopher %c fetches chopstick %d\n", phi,left);
	//如果右边筷子被锁?释放左边,防止死锁
        if(pthread_mutex_trylock(&chopstick[right]) == EBUSY)
        {
            pthread_mutex_unlock(&chopstick[left]);
            continue;//从这儿进入下一次循环(抢左筷子,判断右筷子...)
        }
	//抢到了:
        printf("Philosopher %c fetches chopstick %d\n", phi,right);
        printf("Philosopher %c is eating.\n",phi);
        usleep(10);//进餐
	//之后释放两个筷子
        pthread_mutex_unlock(&chopstick[left]);
        printf("Philosopher %c release chopstick %d\n", phi,left);
        pthread_mutex_unlock(&chopstick[right]);
        printf("Philosopher %c release chopstick %d\n", phi,right);

  • 条件变量
    条件变量类似于 if 语句,等待条件成立时即执行程序。它与互斥锁区别在于,互斥锁用于 上锁 ,条件变量则多用于 等待 。而每个条件变量总是有一个互斥锁与之关联。

  • 异步信号
    信号与任何线程都是异步的,所以到达线程的时间不一定,只有一个线程会被信号选中。并发的多个信号会被不同线程处理。当线程屏蔽该信号时,信号会被挂起,等待其他信号解除屏蔽。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值