例子1:互斥锁 + 条件变量
/*
主线程:创建两个线程,创建完了等待两个线程同步,并等待他们退出
线程1: 1)打印 XXX 2) 如果主程序进入等待状态叫醒他 3) 退出的时候自己回收资源
线程2: 1)打印 XXX 2) 如果主程序进入等待状态叫醒他 3)等待线程1 退出后
*/
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<errno.h>
#include<unistd.h>
#include <string.h>
#include<signal.h>
#define PRINT_ERROR(ret) do{ printf("ERROR: %s: %s\n",__FUNCTION__, strerror(ret)); }while(0);
#define PRINT_ERRORID(ret) do{ printf("%s: %d\n",__FUNCTION__, ret); }while(0);
int g_status=0; // 0: init 1:start wait
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void* thread_1_fun(void*);
void* thread_2_fun(void*);
int main(int argc, char** argv)
{
printf("main: start... \n");
pthread_t thread_1, thread_2;
int ret;
printf("main: creete thread 1... \n");
ret = pthread_create(&thread_1, NULL, thread_1_fun, NULL);
if(ret != 0) PRINT_ERROR(ret);
printf("main: creeate thread 1 end... \n");
printf("main: create thread 2... \n");
ret = pthread_create(&thread_2, NULL, thread_2_fun, &thread_1); // transfer thread 1 id as paramter
if(ret != 0) PRINT_ERROR(ret);
printf("main: creeate thread 2 end... \n");
//这个等待有可能被 线程1 或者 线程2 唤醒
// 由于线程执行的不可预测性,唤醒前有可能收到两个线程发过来的 pthread_cond_signal,但是只有一个起作用
pthread_mutex_lock(&mutex);
printf("main: status 0->1 wait... \n");
g_status = 1;
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
#if 0 //can set status to 2 and let thread 2 to wait and wakeup it
pthread_mutex_lock(&mutex);
printf("main: status 1->2 wait... \n");
g_status = 2;
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
#endif
//pthread_detach(thread_1);//也可以在子程序中 pthread_detach(pthread_self());
ret = pthread_join(thread_1, NULL); //如果这个线程已经结束,返回错误:Invalid argument /如果是一个detach线程,返回错误:No such process
if(ret != 0) PRINT_ERROR(ret);
ret = pthread_join(thread_2, NULL); //等待 进程2结束并回收其占用的资源,8K堆栈
if(ret != 0) PRINT_ERROR(ret);
printf("main: end... \n");
exit(0);
}
void* thread_1_fun(void* arg)
{
printf(" T1: start... \n");
//同步操作,等待主程序创建完线程 并 进入 等待状态
while(1)
{
pthread_mutex_lock(&mutex);
if(g_status == 1)
{
pthread_mutex_unlock(&mutex);
break;
}
pthread_mutex_unlock(&mutex);
}
pthread_mutex_lock(&mutex);
if(g_status == 1)
{
printf(" T1: wakeup main cond signal -> ...\n");
pthread_cond_signal(&cond);
}
pthread_mutex_unlock(&mutex);
printf(" T1: end \n");
// 与主线程分离,线程结束的时候自己释放资源
pthread_detach(pthread_self());
//sleep(1);
/*
//也可以在创建的时候指定这个属性
pthread_attr_t attr;
pthread_t thread;
pthread_attr_init (&attr);pthread_attr_setdetachstat(&attr, PTHREAD_CREATE_DETACHED);
pthread_create (&thread, &attr, &thread_function, NULL);
*/
pthread_exit(0);
}
void* thread_2_fun(void* arg)
{
printf(" T2: start... \n");
//同步操作,等待主程序创建完线程 并 进入 等待状态
while(1)
{
pthread_mutex_lock(&mutex);
if(g_status == 1) //
{
pthread_mutex_unlock(&mutex);
break;
}
pthread_mutex_unlock(&mutex);
}
pthread_mutex_lock(&mutex);
if(g_status == 1)
{
printf(" T2: wakeup main cond signal -> ...\n");
pthread_cond_signal(&cond);
}
pthread_mutex_unlock(&mutex);
//等待线程1结束
pthread_join(*(pthread_t*)arg, NULL);
printf(" T2: end \n");
pthread_exit(0);
}
例子二:信号量
/*
主线程:创建两个线程,创建完了等待两个线程同步,并等待他们退出
线程1: 1)打印 XXX 2) 如果主程序进入等待状态叫醒他 3) 退出的时候自己回收资源
线程2: 1)打印 XXX 2) 如果主程序进入等待状态叫醒他 3)等待线程1 退出后
*/
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<errno.h>
#include<unistd.h>
#include <string.h>
#include<signal.h>
#include <semaphore.h>
#define PRINT_ERROR(ret) do{ printf("ERROR: %s: %s\n",__FUNCTION__, strerror(ret)); }while(0);
sem_t sem1; //子线程等待主线程同步信号
sem_t sem2; //主线程等待子线程同步信号
void* thread_1_fun(void*);
void* thread_2_fun(void*);
int main(int argc, char** argv)
{
printf("main: start... \n");
pthread_t thread_1, thread_2;
int ret;
sem_init(&sem1,0,0);
sem_init(&sem2,0,0);
printf("main: create thread 1... \n");
ret = pthread_create(&thread_1, NULL, thread_1_fun, NULL);
if(ret != 0) PRINT_ERROR(ret);
printf("main: create thread 1 end... \n");
printf("main: creeate thread 2... \n");
ret = pthread_create(&thread_2, NULL, thread_2_fun, &thread_1); // transfer thread 1 id as paramter
if(ret != 0) PRINT_ERROR(ret);
printf("main: creeate thread 2 end... \n");
//同步信号开始
printf("main: send first sync signal to child \n");
sem_post(&sem1);
printf("main: send second sync signal to child \n");
sem_post(&sem1);
// 阻塞并等待被唤醒(确认子线程是否都收到信号)
printf("main: wait sync signal from child thread... \n");
sem_wait(&sem2);
printf("main: receive first sync signal from thread \n");
sem_wait(&sem2);
printf("main: receive second sync signal from thread \n");
//sleep(1);
//如果不等子线程 主线程执行完了之后,子线程也会被系统回收,并结束运行
ret = pthread_join(thread_1, NULL); //如果这个线程已经结束,返回错误:Invalid argument /如果是一个detach线程,返回错误:No such process
if(ret != 0) PRINT_ERROR(ret);
ret = pthread_join(thread_2, NULL); //等待 进程2结束并回收其占用的资源,8K堆栈
if(ret != 0) PRINT_ERROR(ret);
printf("main: end... \n");
exit(0);
}
void* thread_1_fun(void* arg)
{
printf(" T1: start & wait for sync... \n");
sem_wait(&sem1);
printf(" T1: sync OK \n");
printf(" T1: send sync signal to main \n");
sem_post(&sem2);
while(1)
{
printf(" T1: running.. \n");
sleep(1);
}
printf(" T1: end \n");
pthread_exit(0);
}
void* thread_2_fun(void* arg)
{
printf(" T2: start & wait for sync... \n");
sem_wait(&sem1);
printf(" T2: sync OK \n");
printf(" T2: send sync signal to main \n");
sem_post(&sem2);
while(1)
{
printf(" T2: running.. \n");
sleep(1);
}
printf(" T2: end \n");
pthread_exit(0);
}
如下内容来源 https://blog.youkuaiyun.com/u013139008/article/details/78584724
创建线程时的属性设置
1. 线程的调度策略:
SCHED_OTHREAD 非实时调度策略。线程优先级为0,每个线程都不抢占其他的线程。线程会受到时间片的限制。会一直占用系统分配给他的时间片。
SCHED_RR 实时调度策略。线程优先级1-99,数值越大,优先级越高。系统分配给一个线程一个时间片,这个时间片运行过程中不会被打断。但是当时间片运行结束,下一个时间片会分给优先级更高的线程。
SCHED_FIFO 实时调度策略。线程优先级1-99,数值越大,优先级越高。时间片首先分配给优先级最高的线程。一旦时间片分配给一个线程,除非线程主动挂起和退出,该线程会一直占用CPU。线程按照不同的优先级有不同的线程队列。在一个队列中先进先出。
=>实时调度策略会抢占非实时调度策略。除非非实时的线程运行结束,否则实时的线程是不可能得到运行的。
一个进程里面可能有多种调度策略的线程。
pthread_attr_t attr;
struct sched_param param;
param._sched_prority = 10;
pthread_attr_init(&attr);
pthread_attr_setschedpolicy(&attr, SCHED_RR/SCHED_FIFO);
pthread_attr_setschedparam(&attr, ¶m);
pthread_create(xxx, &attr, xxx, xxx);
pthread_attr_destroy(&attr);
2. 线程优先级的作用范围:
PTHREAD_SCOPE_SYSTEM 线程的优先级的作用范围是整个系统。即线程和系统中所有的线程竞争CPU的时间。
PTHREAD_SCOPE_PROCESS 线程的优先级的作用氛围是当前进程。即线程和该进程中其他线程竞争CPU时间。
pthread_attr_t attr;
struct sched_param param;
param._sched_prority = 10;
pthread_attr_init(&attr);
pthread_attr_setschedpolicy(&attr, SCHED_RR/SCHED_FIFO);
pthread_attr_setschedparam(&attr, ¶m);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM/PTHREAD_SCOPE_PROCESS);
pthread_create(xxx, &attr, xxx, xxx);
pthread_destroy(&attr);
3. 线程和其他线程是否分家:
PTHREAD_CREATE_DETACHED 新线程不能用pthread_join函数来同步,而且在退出时自行释放所占用的资源。
PTHREAD_CREATGE_JOINABLE 默认值。可以使用pthread_detach(pthread_id)改变分家状态。
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
4. 线程栈的大小:
栈是线程的属性,在创建线程的时候,可以指定栈的大小。但是程序运行的过程中,栈的大小不能改变。即线程创建出来,大小就确定。
int stack_size;
pthread_attr_setstacksize(&attr, stack_size);
pthread_attr_getstacksize(&attr, &stack_size);
PTHREAD_STACK_MIN 栈的最小值
...