原文:https://www.cnblogs.com/yorkyang/p/7804733.html

线程的优点:

  • 减少系统调度开销,不占有独立的资源,切换速度快,执行效率高。
  • 线程间通信方便,可共享资源。
  • 改善程序设计结构,功能复杂的进程可以分为多个独立的线程分别执行,模块性更强。

  线程分为:用户态线程和核心态线程。

  用户态的多线程程序在运行时不许要特定的内核支持,同一个进程的线程之间进行切换时,不需要调用系统调用。

  核心态线程的实现方法允许不同进程中的的线程按照相同的调度方法进行调度,有利于发挥多处理器的并发优势。

线程创建:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*),void *arg);
//thread 指向线程标识符的指针,使用这个标识符来引用新线程
//attr 设置线程属性,设为NULL则生成默认属性的线程
//start_routine 线程运行函数的起始位置
//arg 线程运行函数的参数

线程终止:

1.通过线程自身结束

void pthread_exit(void *rval_ptr);
//rval_ptr是函数的返回代码,相当于线程的退出码 2.通过同一进程的其他线程来结束 int pthread_cancel(pthread_t tid);
//tid是要结束线程的标识符

下面的函数用于阻塞等待一个线程的结束

int pthread_join(pthread_t thread, void **return_ptr)
//创建线程,输出当前系统的时间

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<unistd.h>
#include<pthread.h> void print_currentTime(void)
{
time_t ct;
ct=time(NULL);
//ctime:将秒数转换成字符串
printf("current time is : '%s'",ctime(&ct));
pthread_exit("Time thread finished!\n");
} int main()
{
int ret;
void *thread_result;
pthread_t new_thread; ret=pthread_create(&new_thread,NULL,(void*)print_currentTime,NULL);
if(ret!=0){
perror("thread creation failed!\n");
exit(EXIT_FAILURE);
} printf("waiting for new thread....\n");
ret=pthread_join(new_thread,&thread_result);
if(ret!=0){
perror("thread join failed!\n");
exit(EXIT_FAILURE);
} printf("thread joined, returned: %s\n",(char*)thread_result);
return 0;
}
//编译时候注意: gcc thread_date.c -o thread_date -lpthread

线程属性:

线程属性主要包括分离属性,绑定属性,调度属性,堆栈属性,继承属性等,结构为pthread_attr_t。

属性设置函数:

int pthread_attr_init(pthread_attr_t *attr)
//attr是指向属性结构的指针
//注意:此函数必须在调用pthread_creater()函数之前调用

这里提到了一个概念“轻进程(Light Weight Process, LWP)”,位于用户层与系统层之间的内核线程。系统对线程资源的分配以及对线程的控制是通过轻进程来实现的,一个轻进程可以控制一个或多个线程。

获取线程绑定状态函数:

int pthread_attr_getscope(pthread_attr_t *attr, int *scope)
//scope返回绑定属性的状态

设置线程绑定属性函数:

int pthread_attr_setscope(pthread_attr_t* attr, int scope)
//scope是要绑定的类型

获得线程优先级函数:

int pthread_attr_getschedparam(pthread_attr_t *attr, const struct sched_param *param)
//param中存放线程的调度参数信息

设置线程优先级函数:

int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param)

获取调度策略函数:

int pthread_attr_getschedpolicy(pthread_attr *attr, int *policy)
//调度策略存放在policy中

设置调度策略函数:

int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)

获取并发级别函数:

int pthread_getconcurrency(void)

设置并发级别函数:

int pthread_setconcurrency(int new_level)

多线程同步技术:

线程同步机制主要有:互斥量,信号量,条件变量,读写锁等。

互斥量:

数据类型为pthread_mytex_t,主要函数:

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
int pthread_mutex_lock(pthread_mutex_t *mutex); //阻塞调用
int pthread_mutex_trylock(pthread_mutex_t *mutex); //非阻塞调用
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
//mutex是定义的pthread_mutex_t的指针,mutex_attr是互斥量的属性结构

例子:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<string.h> pthread_mutex_t mutex;
int count=0;
char msg_buf[64]; void setMsg_Func(void)
{
while(count>0){
pthread_mutex_lock(&mutex);
memset(msg_buf,0,64);
sprintf(msg_buf,"count=%d.\n",count--);
pthread_mutex_unlock(&mutex);
srand((int)time(0));
sleep(rand()%3);
}
pthread_exit(0);
} void printMsg_Func(void)
{
while(count>=0){
pthread_mutex_lock(&mutex);
printf("%s",msg_buf);
pthread_mutex_unlock(&mutex);
if(0==count)
break;
srand((int)time(0));
sleep(rand()%3);
}
} int main()
{
int ret;
pthread_t set_thread;
count=4;
pthread_mutex_init(&mutex,NULL);
ret=pthread_create(&set_thread,NULL,(void*)&setMsg_Func,NULL);
if(ret!=0){
perror("thread creation failed!\n");
exit(EXIT_FAILURE);
} printMsg_Func();
ret=pthread_join(set_thread,NULL);
if(ret!=0){
perror("thread creation failed!\n");
exit(EXIT_FAILURE);
}
printf("Finished!\n");
pthread_mutex_destroy(&mutex);
return 0;
}

但是要注意,如果使用互斥量过程中,如果两个线程试图同时占用两个资源,并锁定,可能造成死锁。

条件变量:

  只使用互斥量很可能造成死锁,为此可以加入条件变量。条件变量允许线程阻塞和等待另一个线程发送信号,使用条件变量可以以原子方式阻塞线程,直到满足某个条件为止。

  互斥量主要用来保证对临界区的互斥进入,而条件变量则用于线程的阻塞等待。

int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);     //创建条件变量
int pthread_cond_signal(pthread_cond_t *cond); //用来释放被阻塞在条件变量cond上的进程
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); //使线程阻塞
int pthread_cond_broadcast(pthread_cond_t *cond); //用来唤醒所有阻塞在条件变量cond上的线程
int pthread_cond_timewait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
//使线程阻塞,与wait不同,它经过abstime时间后,无论条件是否满足,都会释放 int pthread_cond_destroy(pthread_cond_t *cond); //cond是一个指向结构pthread_cond_t的指针
//cond_attr是条件变量的属性结构指针

例子:

//创建两个线程,偶数时进程1给变量加1,奇数时进程2给变量加1
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h> #define MAX_COUNT 9 pthread_mutex_t mutex;
pthread_cond_t cond;
int count=0; void addCount_odd_Func(void)
{
pthread_mutex_lock(&mutex);
while(count<MAX_COUNT){
if(count%2==1){
count++;
printf("addcout_odd_Func():count=%d.\n",count);
pthread_cond_signal(&cond);
}
else
pthread_cond_wait(&cond,&mutex);
}
pthread_mutex_unlock(&mutex);
} void addCount_even_Func(void)
{
pthread_mutex_lock(&mutex);
while(count<MAX_COUNT){
if(count%2==0){
count++;
printf("addCount_even_Func:count=%d.\n",count);
pthread_cond_signal(&cond);
}
else
pthread_cond_wait(&cond,&mutex);
}
pthread_mutex_unlock(&mutex);
} int main(int argc, char **argv)
{
int ret;
pthread_t odd_thread,even_thread;
pthread_attr_t thread_attr;
count=0; pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
ret=pthread_attr_init(&thread_attr);
if(ret!=0){
perror("attribute creation failed!");
exit(EXIT_FAILURE);
} pthread_attr_setdetachstate(&thread_attr,PTHREAD_CREATE_DETACHED); ret=pthread_create(&odd_thread,&thread_attr,(void*)&addCount_odd_Func,NULL);
if(ret!=0){
perror("thread creation failed!");
exit(EXIT_FAILURE);
} ret=pthread_create(&even_thread,&thread_attr,(void*)&addCount_even_Func,NULL);
if(ret!=0){
perror("thread creation failed!");
exit(EXIT_FAILURE);
} while(count<MAX_COUNT); printf("Finished!");
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex); return 0;
}

C语言中的多线程的更多相关文章

  1. C语言中的多线程编程

    很久很久以前,我对C语言的了解并不是很多,我最早听说多线程编程是用Java,其实C语言也有多线程编程,而且更为简单.方便.强大.下面就让我们简单领略一下Unix C语言环境下的多线程编程吧! 下面先看 ...

  2. C语言中关键字volatile的含义【转】

    本文转载自:http://m.jb51.net/article/37489.htm 本篇文章是对C语言中关键字volatile的含义进行了详细的分析介绍,需要的朋友参考下 volatile 的意思是“ ...

  3. C/C++——C++变量的作用域与生命周期,C语言中变量的作用域和生命周期

    全局变量 作用域:全局作用域(全局变量只需在一个源文件中定义,就可以作用于所有的源文件.) 生命周期:程序运行期一直存在 引用方法:其他文件中要使用必须用extern 关键字声明要引用的全局变量. 内 ...

  4. Java中的多线程总结(转)

      1.多线程概述 当一个程序运行时,内部可能包含了多个顺序执行流,每个顺序执行流就是一个线程.主要以下几个优点: 线程之间很容易实现共享内存 创建线程代价较小 Java语言内置多线程功能支持 2.线 ...

  5. Go语言中的管道(Channel)总结

    管道(Channel)是Go语言中比较重要的部分,经常在Go中的并发中使用.今天尝试对Go语言的管道来做以下总结.总结的形式采用问答式的方法,让答案更有目的性. Q1.管道是什么? 管道是Go语言在语 ...

  6. C语言中关键字auto、static、register、const、volatile、extern的作用

    原文:C语言中关键字auto.static.register.const.volatile.extern的作用 关键字auto.static.register.const.volatile.exter ...

  7. OS X 和iOS 中的多线程技术(下)

    OS X 和iOS 中的多线程技术(下) 上篇文章中介绍了 pthread 和 NSThread 两种多线程的方式,本文将继续介绍 GCD 和 NSOperation 这两种方式.. 1.GCD 1. ...

  8. 【worker】js中的多线程

    因为下个项目中要用到一些倒计时的功能,所以就提前准备了一下,省的到时候出现一下界面不友好和一些其他的事情.正好趁着这个机会也加深一下html5中的多线程worker的用法和理解. Worker简介 J ...

  9. C语言编程(多线程)

    C语言中多线程编程包括的文件:#include<pthread.h>(linux环境下) pthread_t //线程函数返回类型 pthread_mutrex_t //互斥锁类型 int ...

随机推荐

  1. vue+axios通过formdata提交参数和上传文件

    demo.vue 文件 <template> <div class="demo"> <input v-model="importForm.m ...

  2. python——操作系统的发展史

    一.手工操作 —— 穿孔卡片 1946年第一台计算机诞生--20世纪50年代中期,计算机工作还在采用手工操作方式.此时还没有操作系统的概念.    程序员将对应于程序和数据的已穿孔的纸带(或卡片)装入 ...

  3. 《阿里巴巴 Java 开发规约》自动化检测插件安装及体验

    2017 开春之际,有助于提高行业编码规范化水平的<阿里巴巴 Java 开发手册>首次面世.汇聚阿里集团近万名技术精英的经验知识,这套高含金量的手册一经公开,便引起业界普遍关注和学习. 历 ...

  4. Vue学习官网和Vue的书籍 目录结构

    Vue基础知识学习网站[中文] https://cn.vuejs.org/v2/guide/ Vue路由知识学习网站[中文] https://router.vuejs.org/zh/guide/  V ...

  5. extjs6 创建工程和打包发布

    准备工作: 下载extjs6的开发包,我这里是试验版:ext-6.6.0-trial.zip.解压到某个目录,我这里解压到:D:\tools\about-ext\ext-6.6.0-trial 目录下 ...

  6. c# 调试过程

  7. Python_逻辑运算符

    1.逻辑运算符

  8. jmeter 5.1.1版本 进行抓包的时候弹出输入密码

    先描述一下如何配置Jmeter 先新建一个Thread Group,比如我命令为抓包 新建一个HTTP(S) Test Script Recorder,进行如下的配置, 配置端口,我这边设置为8899 ...

  9. unity之中级必备知识

    Mask,Scroll Rect实现图拖拽:新建Imag,添加Mask,Scroll Rect组件:新建Image,托放在Scroll下的Content:新建Scroll Bar实现滚动条的同步:托放 ...

  10. JDK环境变量配置linux

    安装前先查看是否安装过jdk如果安装过则 卸载 1. 确定JDK的版本: rpm -qa | grep jdk rpm -qa | grep gcj 可能的结果是: libgcj-4.1.2-42.e ...