C语言中的多线程
原文: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;
}
人就像是被蒙着眼推磨的驴子,生活就像一条鞭子;当鞭子抽到你背上时,你就只能一直往前走,虽然连你也不知道要走到什么时候为止,便一直这么坚持着。