我们如何控制调度 C、C++ 中的线程执行?
感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持!❤️
摘要:
线程调度,内存管理在C/C++开发中是必不可少的,本文旨在通过C/C++的代码控制调度线程执行,前两个示例使用 C 语言编写,最后一个示例使用 C++ 语言编写。在第一种方法中,我使用了3个互斥锁和3个条件变量,在第二种方法中,使用全局变量作为控制器来控制线程,而第三个示例是用 C++ 编写的,使用的方法与第一个C示例中的方法相同。
关键词
: c,c++,线程调度
声明:
本文作者原创,转载请附上文章出处与本文链接。
文章目录
- 摘要:
- Ⅰ.1 第一个示例
- Ⅰ.2 第二个示例
- Ⅱ.1 第三个示例
Ⅰ.1 第一个示例
首先,查看 C 下面的第一个线程。这里它锁定了互斥锁 lock1(以便其他线程无法访问代码)开始执行(未添加代码,仅添加注释),最后在完成等待 cond1 的任务后,同样,第二个线程锁定了互斥锁 lock2,开始执行其业务逻辑,最后等待 cond2 的条件,第三个线程锁定了互斥锁 lock3,开始执行其业务逻辑,最后等待 cond3 的条件。
我没有在这里添加任何业务逻辑,因为这只是一个例子。在注释掉的部分中,可以添加将以并行模式执行的业务逻辑。假设线程 3 依赖于线程 1 的最终输出(将插入表中),线程 3 将在创建其最终结果之前读取该信息,而线程 2 依赖于线程 3 的最终结果来生成其最终结果。因此,线程 1 在将数据插入表中后,通过条件变量向线程 3 发出信号,以继续其最终过程。这意味着线程 1 控制线程 3。由于线程 2 依赖于线程 3 的最终结果,因此线程 3 控制线程 2 的执行。在这里,我们可以允许线程 1 独立执行,因为它的操作不依赖于任何其他线程,但是对于线程控制,我们在这里要控制所有线程,因此,线程 1 由线程 2 控制。
要启动控制过程,我们首先释放线程 1。在主线程(即主函数,每个程序都有一个主线程,在 C/C++ 中,一旦控制权通过内核传递给主方法/函数,此主线程将由操作系统自动创建)中,我们调用pthread_cond_signal(&cond1);
。从主线程调用此函数后,等待条件 1 的线程 1 将被释放并开始进一步执行。完成最终任务后,它将调用pthread_cond_signal(&cond3);
。现在,等待条件 3 的线程(即线程 3)将被释放,并开始执行其最后阶段,并将调用pthread_cond_signal(&cond2);
它将释放等待条件 2 的线程(在本例中为线程 2)。这是我们在多线程环境中调度和控制线程执行的方式。
#include<pthread.h>
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond3 = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock3 = PTHREAD_MUTEX_INITIALIZER;
int TRUE = 1;
void print(char *p)
{
printf("%s",p);
}
void * threadMethod1(void *arg)
{
printf("In thread1\n");
do{
pthread_mutex_lock(&lock1);
//Add your business logic(parallel execution codes) here
pthread_cond_wait(&cond1, &lock1);
printf("I am thread1 generating the final report and inserting into a table \n");
pthread_cond_signal(&cond3);/* Now allow 3rd thread to process */
pthread_mutex_unlock(&lock1);
}while(TRUE);
pthread_exit(NULL);
}
void * threadMethod2(void *arg)
{
printf("In thread2\n");
do
{
pthread_mutex_lock(&lock2);
//Add your business logic(parallel execution codes) here
pthread_cond_wait(&cond2, &lock2);
printf("I am thread2 generating the final report and inserting into a table \n");
pthread_cond_signal(&cond1);
pthread_mutex_unlock(&lock2);
}while(TRUE);
pthread_exit(NULL);
}
void * threadMethod3(void *arg)
{
printf("In thread3\n");
do
{
pthread_mutex_lock(&lock3);
//Add your business logic(parallel execution codes) here
pthread_cond_wait(&cond3, &lock3);
printf("I am thread3 generating the final report and inserting into a table \n");
pthread_cond_signal(&cond2);
pthread_mutex_unlock(&lock3);
}while(TRUE);
pthread_exit(NULL);
}
int main(void)
{
pthread_t tid1, tid2, tid3;
int i = 0;
printf("Before creating the threads\n");
if( pthread_create(&tid1, NULL, threadMethod1, NULL) != 0 )
printf("Failed to create thread1\n");
if( pthread_create(&tid2, NULL, threadMethod2, NULL) != 0 )
printf("Failed to create thread2\n");
if( pthread_create(&tid3, NULL, threadMethod3, NULL) != 0 )
printf("Failed to create thread3\n");
pthread_cond_signal(&cond1);/* Now allow first thread to process first */
sleep(1);
TRUE = 0;/* Stop all the thread */
sleep(3);
/* this is how we join thread before exit from a system */
/*
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_join(tid3,NULL);*/
exit(0);
}
Ⅰ.2 第二个示例
在 C 第二种方法中,我使用全局变量 controller 作为控制器来控制线程。请仔细观察下面的示例,看看它是如何基于全局变量进行调度/控制的。但更好的方法是第一个例子,下面的内容只是为了理解,逻辑主要观察 while 循环内的“if 条件”即可,此程序的运行顺序为线程 3 -》线程 1 -》线程 2。
#include<pthread.h>
int controller = 0;
void print(char *p)
{
printf("%s",p);
}
void * threadMethod1(void *arg)
{
while(1)
{
if(controller == 3)
break;
}
print("I am thread 1st\n");
controller = 1;
pthread_exit(NULL);
}
void * threadMethod2(void *arg)
{
while(1)
{
if(controller == 1)
break;
}
print("I am thread 2nd\n");
controller = 2;
pthread_exit(NULL);
}
void * threadMethod3(void *arg)
{
while(1)
{
if(controller == 0)
break;
}
print("I am thread 3rd\n");
controller = 3;
pthread_exit(NULL);
}
int main(void)
{
pthread_t tid1, tid2, tid3;
int i = 0;
printf("Before creating the threads\n");
if( pthread_create(&tid1, NULL, threadMethod1, NULL) != 0 )
printf("Failed to create thread1\n");
if( pthread_create(&tid2, NULL, threadMethod2, NULL) != 0 )
printf("Failed to create thread2\n");
sleep(3);
if( pthread_create(&tid3, NULL, threadMethod3, NULL) != 0 )
printf("Failed to create thread3\n");
/*
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_join(tid3,NULL);*/
sleep(10);
exit(0);
}
Ⅱ.1 第三个示例
现在,我的第三个示例是用 C++ 编写的,这里使用的方法与第一个 C 示例中的方法相同,如果你直接看到这个示例,请阅读用 C 编写的第一个示例以了解该方法。下面的示例是在 Visual Studio 2013 中开发的代码,并且没有将代码分发到单独的头文件和 CPP 文件中。此外,我已经以内联方式声明和定义了所有方法,因为这仅仅是一个例子。此外,您可能会想,“为什么我要声明三个类,而类结构却是相同的?”不要混淆,我使用相同的类定义只是为了举例。查看业务逻辑的注释行,这里,每个类都有不同的业务功能和逻辑。这个例子针对的是三个不同的线程和三个不同的类,假设所有的类都是不同的,具有不同的功能和业务逻辑。
#include "stdafx.h"//remove this header file if you are compiling with different compiler
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
#include "windows.h"//remove this header file if you are compiling with different compiler
std::condition_variable _tcond1;
std::condition_variable _tcond2;
std::condition_variable _tcond3;
class SimpleThread1
{
private:
std::mutex _lockprint;
bool isThreadAlive = true;
public:
SimpleThread1(){}
SimpleThread1(SimpleThread1 &st){};
void StartProcessing()
{
std::unique_lock<std::mutex> locker(_lockprint);
//Add your business logic(parallel execution codes) here
_tcond1.wait(locker);
std::cout << "I am thread :1"<<std::endl;
_tcond3.notify_one();
}
void operator()()
{
while (isThreadAlive)
StartProcessing();
}
void stopeThread()
{
isThreadAlive = false;
}
};
class SimpleThread2
{
private:
std::mutex _lockprint;
bool isThreadAlive = true;
public:
SimpleThread2(){}
SimpleThread2(SimpleThread2 &st) {};
void StartProcessing()
{
std::unique_lock<std::mutex> locker(_lockprint);
//Add your business logic(parallel execution codes) here
_tcond2.wait(locker);
std::cout << "I am thread :2"<< std::endl;
_tcond1.notify_one();
}
void operator()()
{
while (isThreadAlive)
StartProcessing();
}
void stopeThread()
{
isThreadAlive = false;
}
};
class SimpleThread3
{
private:
std::mutex _lockprint;
bool isThreadAlive = true;
public:
SimpleThread3(){}
SimpleThread3(SimpleThread3 &st) {};
void StartProcessing()
{
std::unique_lock<std::mutex> locker(_lockprint);
//Add your business logic(parallel execution codes) here
_tcond3.wait(locker);
std::cout << "I am thread :3"<< std::endl;
_tcond2.notify_one();
}
void operator()()
{
while (isThreadAlive)
StartProcessing();
}
void stopeThread()
{
isThreadAlive = false;
}
};
int main()
{
SimpleThread1 st1;
SimpleThread2 st2;
SimpleThread3 st3;
std::thread t1(st1);
std::thread t2(st2);
std::thread t3(st3);
_tcond1.notify_one();
t1.detach();
t2.detach();
t3.detach();
Sleep(1000);//replace it with sleep(10) for linux/unix
st1.stopeThread();
st2.stopeThread();
st3.stopeThread();
return 0;
}
end~