C 此解决方案中的信号量使用是否正确?
问题: 我必须增加x1和x2变量,这应该由单独的线程完成,并且在两个变量的前一个增量都未完成之前,不应该调用这两个变量的下一个增量 建议的解决方案: 初始化4个信号量并为变量的单独增量调用单独的线程。2个信号量用于向线程传递消息以开始递增,2个信号量用于向主线程传递递增已完成的消息。主线程将等待来自两个子线程的信号量发布,显示两个变量的增量都已完成,然后主线程将消息传递给两个子线程,以允许进一步增量 这个对我来说很好用。但是,有人能提出更好的解决方案吗?或者,有人能指出这个解决方案中的问题吗? 任何帮助都将不胜感激?提前谢谢 解决方案代码:C 此解决方案中的信号量使用是否正确?,c,multithreading,semaphore,C,Multithreading,Semaphore,问题: 我必须增加x1和x2变量,这应该由单独的线程完成,并且在两个变量的前一个增量都未完成之前,不应该调用这两个变量的下一个增量 建议的解决方案: 初始化4个信号量并为变量的单独增量调用单独的线程。2个信号量用于向线程传递消息以开始递增,2个信号量用于向主线程传递递增已完成的消息。主线程将等待来自两个子线程的信号量发布,显示两个变量的增量都已完成,然后主线程将消息传递给两个子线程,以允许进一步增量 这个对我来说很好用。但是,有人能提出更好的解决方案吗?或者,有人能指出这个解决方案中的问题吗?
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
//Threads
pthread_t pth1,pth2;
//Values to calculate
int x1 = 0, x2 = 0;
sem_t c1,c2,c3,c4;
void *threadfunc1(void *parm)
{
for (;;) {
x1++;
sem_post(&c1);
sem_wait(&c3);
}
return NULL ;
}
void *threadfunc2(void *parm)
{
for (;;) {
x2++;
sem_post(&c2);
sem_wait(&c4);
}
return NULL ;
}
int main () {
sem_init(&c1, 0, 0);
sem_init(&c2, 0, 0);
sem_init(&c3, 0, 0);
sem_init(&c4, 0, 0);
pthread_create(&pth1, NULL, threadfunc1, "foo");
pthread_create(&pth2, NULL, threadfunc2, "foo");
sem_wait(&c1);
sem_wait(&c2);
sem_post(&c3);
sem_post(&c4);
int loop = 0;
while (loop < 8) {
// iterated as a step
loop++;
printf("Initial : x1 = %d, x2 = %d\n", x1, x2);
sem_wait(&c1);
sem_wait(&c2);
printf("Final : x1 = %d, x2 = %d\n", x1, x2);
sem_post(&c3);
sem_post(&c4);
}
sem_wait(&c1);
sem_wait(&c2);
sem_destroy(&c1);
sem_destroy(&c2);
sem_destroy(&c3);
sem_destroy(&c4);
printf("Result : x1 = %d, x2 = %d\n", x1, x2);
pthread_cancel(pth1);
pthread_cancel(pth2);
return 1;
}
#包括
#包括
#包括
//线程
pthread_t pth1,pth2;
//要计算的值
int-x1=0,x2=0;
扫描电镜c1、c2、c3、c4;
void*threadfunc1(void*parm)
{
对于(;;){
x1++;
sem_post(&c1);
sem_wait(&c3);
}
返回NULL;
}
void*threadfunc2(void*parm)
{
对于(;;){
x2++;
sem_post(&c2);
sem_-wait(&c4);
}
返回NULL;
}
int main(){
sem_init(&c1,0,0);
sem_init(&c2,0,0);
sem_init(&c3,0,0);
sem_init(&c4,0,0);
pthread_create(&pth1,NULL,threadfunc1,“foo”);
pthread_create(&pth2,NULL,threadfunc2,“foo”);
sem_wait(&c1);
sem_wait(&c2);
sem_post(&c3);
sem_post(&c4);
int循环=0;
while(循环<8){
//作为一个步骤迭代
loop++;
printf(“首字母:x1=%d,x2=%d\n”,x1,x2);
sem_wait(&c1);
sem_wait(&c2);
printf(“最终:x1=%d,x2=%d\n”,x1,x2);
sem_post(&c3);
sem_post(&c4);
}
sem_wait(&c1);
sem_wait(&c2);
sem_破坏(&c1);
sem_破坏(&c2);
sem_破坏(&c3);
sem_破坏(&c4);
printf(“结果:x1=%d,x2=%d\n”,x1,x2);
pthread_cancel(pth1);
pthread_cancel(pth2);
返回1;
}
程序的问题在于,您正在同步线程以使其彼此同步运行。在每个线程中,在每次迭代中,递增一个计数器,然后调用两个同步原语。因此,循环体中超过一半的时间用于同步
在您的程序中,计数器实际上彼此无关,因此它们实际上应该彼此独立运行,这意味着每个线程实际上可以在迭代过程中进行实际计算,而不是主要进行同步
对于输出要求,您可以允许每个线程将每个子计算放入主线程可以读取的数组中。主线程等待每个线程完全完成,然后可以读取每个数组以创建输出
void *threadfunc1(void *parm)
{
int *output = static_cast<int *>(parm);
for (int i = 0; i < 10; ++i) {
x1++;
output[i] = x1;
}
return NULL ;
}
void *threadfunc2(void *parm)
{
int *output = static_cast<int *>(parm);
for (int i = 0; i < 10; ++i) {
x2++;
output[i] = x2;
}
return NULL ;
}
int main () {
int out1[10];
int out2[10];
pthread_create(&pth1, NULL, threadfunc1, out1);
pthread_create(&pth2, NULL, threadfunc2, out2);
pthread_join(pth1, NULL);
pthread_join(pth2, NULL);
int loop = 0;
while (loop < 9) {
// iterated as a step
loop++;
printf("Final : x1 = %d, x2 = %d\n", out1[loop], out2[loop]);
}
printf("Result : x1 = %d, x2 = %d\n", out1[9], out2[9]);
return 1;
}
void*threadfunc1(void*parm)
{
int*output=static_cast(parm);
对于(int i=0;i<10;++i){
x1++;
输出[i]=x1;
}
返回NULL;
}
void*threadfunc2(void*parm)
{
int*output=static_cast(parm);
对于(int i=0;i<10;++i){
x2++;
输出[i]=x2;
}
返回NULL;
}
int main(){
int out1[10];
int out2[10];
pthread_create(&pth1,NULL,threadfunc1,out1);
pthread_create(&pth2,NULL,threadfunc2,out2);
pthread_join(pth1,NULL);
pthread_join(pth2,NULL);
int循环=0;
while(循环<9){
//作为一个步骤迭代
loop++;
printf(“最终:x1=%d,x2=%d\n”,out1[loop],out2[loop]);
}
printf(“结果:x1=%d,x2=%d\n”,out1[9],out2[9]);
返回1;
}
而不是有一组线程来做X1的事情,暂停它们,然后有一组线程做X2的事情,考虑线程池。线程池是一组线程,它们处于空闲状态,直到您有工作要做,然后它们解除暂停并完成工作
这个系统的一个优点是它使用条件变量和互斥量而不是信号量。在许多系统上,互斥比信号量更快(因为它们更有限)
//任务是一个抽象类,描述“可以完成的事情”,它
//可以放入工作队列中
课堂任务
{
公众:
虚空运行()=0;
};
//如果需要,可以使其更面向对象。。。这只是一个例子。
//工作队列
结构工作队列
{
std::vector queue;//必须持有互斥体才能访问队列
bool finished;//如果设置为true,threadpoolRun将开始退出
pthread_mutex_t mutex;
pthread_cond_t hasWork;//如果可能还有更多的事情要做,则会通知此条件
pthread_cond_t doneWithWork;//如果工作队列可能为空,则会发出此条件的信号
};
void线程池运行(void*queuePtr)
{
//threadpoolRun的参数始终是一个工作队列*
WorkQueue&WorkQueue=*动态_转换(queuePtr);
pthread_mutex_lock(&workQueue.mutex);
//前提条件:每次我们开始这个while循环时,我们必须有
//互斥。
而(!workQueue.finished){
//试着找工作。如果没有,我们就等到有人发信号说有工作
if(workQueue.queue.empty()){
//空。等待另一个线程发出可能有工作的信号
//但在此之前,先向主线程发出队列可能为空的信号
pthread_cond_广播(&workQueue.doneWithWOrk);
pthread_cond_wait(&workQueue.hasWork,&workQueue.mutex);
}否则{
//还有工作要做。抓取任务,释放互斥锁(以便
//其他线程可以从工作队列中获取内容),然后开始工作!
Task*myTask=workQueue.queue.back();
workQueue.queue.pop_返回(
// a task is an abstract class describing "something that can be done" which
// can be put in a work queue
class Task
{
public:
virtual void run() = 0;
};
// this could be made more Object Oriented if desired... this is just an example.
// a work queue
struct WorkQueue
{
std::vector<Task*> queue; // you must hold the mutex to access the queue
bool finished; // if this is set to true, threadpoolRun starts exiting
pthread_mutex_t mutex;
pthread_cond_t hasWork; // this condition is signaled if there may be more to do
pthread_cond_t doneWithWork; // this condition is signaled if the work queue may be empty
};
void threadpoolRun(void* queuePtr)
{
// the argument to threadpoolRun is always a WorkQueue*
WorkQueue& workQueue= *dynamic_cast<WorkQueue*>(queuePtr);
pthread_mutex_lock(&workQueue.mutex);
// precondition: every time we start this while loop, we have to have the
// mutex.
while (!workQueue.finished) {
// try to get work. If there is none, we wait until someone signals hasWork
if (workQueue.queue.empty()) {
// empty. Wait until another thread signals that there may be work
// but before we do, signal the main thread that the queue may be empty
pthread_cond_broadcast(&workQueue.doneWithWOrk);
pthread_cond_wait(&workQueue.hasWork, &workQueue.mutex);
} else {
// there is work to be done. Grab the task, release the mutex (so that
// other threads can get things from the work queue), and start working!
Task* myTask = workQueue.queue.back();
workQueue.queue.pop_back(); // no one else should start this task
pthread_mutex_unlock(&workQueue.mutex);
// now that other threads can look at the queue, take our time
// and complete the task.
myTask->run();
// re-acquire the mutex, so that we have it at the top of the while
// loop (where we need it to check workQueue.finished)
pthread_mutex_lock(&workQueue.mutex);
}
}
}
// Now we can define a bunch of tasks to do your particular problem
class Task_x1a
: public Task
{
public:
Task_x1a(int* inData)
: mData(inData)
{ }
virtual void run()
{
// do some calculations on mData
}
private:
int* mData;
};
class Task_x1b
: public Task
{ ... }
class Task_x1c
: public Task
{ ... }
class Task_x1d
: public Task
{ ... }
class Task_x2a
: public Task
{ ... }
class Task_x2b
: public Task
{ ... }
class Task_x2c
: public Task
{ ... }
class Task_x2d
: public Task
{ ... }
int main()
{
// bet you thought you'd never get here!
static const int numberOfWorkers = 4; // this tends to be either the number of CPUs
// or CPUs * 2
WorkQueue workQueue; // create the workQueue shared by all threads
pthread_mutex_create(&workQueue.mutex);
pthread_cond_create(&workQueue.hasWork);
pthread_cond_create(&workQueue.doneWithWork);
pthread_t workers[numberOfWorkers];
int data[10];
for (int i = 0; i < numberOfWorkers; i++)
pthread_create(&pth1, NULL, &threadpoolRun, &workQueue);
// now all of the workers are sitting idle, ready to do work
// give them the X1 tasks to do
{
Task_x1a x1a(data);
Task_x1b x1b(data);
Task_x1c x1c(data);
Task_x1d x1d(data);
pthread_mutex_lock(&workQueue.mutex);
workQueue.queue.push_back(x1a);
workQueue.queue.push_back(x1b);
workQueue.queue.push_back(x1c);
workQueue.queue.push_back(x1d);
// now that we've queued up a bunch of work, we have to signal the
// workers that the work is available
pthread_cond_broadcast(&workQueue.hasWork);
// and now we wait until the workers finish
while(!workQueue.queue.empty())
pthread_cond_wait(&workQueue.doneWithWork);
pthread_mutex_unlock(&workQueue.mutex);
}
{
Task_x2a x2a(data);
Task_x2b x2b(data);
Task_x2c x2c(data);
Task_x2d x2d(data);
pthread_mutex_lock(&workQueue.mutex);
workQueue.queue.push_back(x2a);
workQueue.queue.push_back(x2b);
workQueue.queue.push_back(x2c);
workQueue.queue.push_back(x2d);
// now that we've queued up a bunch of work, we have to signal the
// workers that the work is available
pthread_cond_broadcast(&workQueue.hasWork);
// and now we wait until the workers finish
while(!workQueue.queue.empty())
pthread_cond_wait(&workQueue.doneWithWork);
pthread_mutex_unlock(&workQueue.mutex);
}
// at the end of all of the work, we want to signal the workers that they should
// stop. We do so by setting workQueue.finish to true, then signalling them
pthread_mutex_lock(&workQueue.mutex);
workQueue.finished = true;
pthread_cond_broadcast(&workQueue.hasWork);
pthread_mutex_unlock(&workQueue.mutex);
pthread_mutex_destroy(&workQueue.mutex);
pthread_cond_destroy(&workQueue.hasWork);
pthread_cond_destroy(&workQueue.doneWithWork);
return data[0];
}