原文: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;
}

最新文章

  1. HTML结构化
  2. MongoDB-JAVA-Driver 3.2版本常用代码全整理(4) - 地理空间索引
  3. Log4Net根据不同的Logger名称,生成日志文件到不同的地方。
  4. 【翻译四】java-并发之线程暂停
  5. mysql 大小写 整理
  6. js默认比较第一个数字大小
  7. slot的含义
  8. xml&lt;&gt;编译
  9. hdu2012
  10. 转载JSON格式化工具
  11. flash引入
  12. linux 工具: Top
  13. -bash: warning: setlocale: LC_CTYPE: cannot change locale (EN_US.UTF-8): No such file or directory
  14. Windows cmd命令反斜杠问题
  15. vue学习笔记(四)- cmd无法识别vue命令解决方法
  16. linux文本编辑器vim大全
  17. SQL Server基础之登陆触发器
  18. python3-面向对象进阶(内置方法)
  19. JavaScript原型、闭包、继承和原型链等等总结
  20. loading加载的代码

热门文章

  1. 使用node建立本地服务器访问静态文件
  2. 使用Idea初始化一个spring boot 项目
  3. sql server 游标和with as使用
  4. Ubuntu18.04开机启动sudo命令
  5. Nuget &amp; VS Plugin
  6. 现在记录几款好用的vscode的插件
  7. C++——inline function
  8. 聊天程序——基于Socket、Thread (二)
  9. vue---子调父 $emit (把子组件的数据传给父组件)
  10. Mybatis3.0-[tp_28-29]-映射文件-resultMap_自定义结果集映射规则_及关联环境的搭建