使线程按顺序重做打印功能

时间:2014-05-10 14:02:00

标签: c++ multithreading

这是家庭作业 必须按顺序打印一个字符串(给定为输入)由多个线程按顺序打印(作为输入的大小)1,2,3,1,2,3,1,2(线程数给出为输入)。 一个线程在创建时执行此打印功能,我希望它在所有其他线程之后重做它。我面临两个问题:
 1.线程不按固定顺序打印(我的给出1,3,2,4见输出)
 2.线程需要重新打印,直到整个字符串耗尽。

这就是我试过的......

  #include<iostream>
#include<mutex>
#include<thread>
#include<string>
#include<vector>
#include<condition_variable>
#include<chrono>

using namespace std;
class circularPrint{
    public:
    int pos;
    string message;
    int nCharsPerPrint;
    mutex mu;
    condition_variable cv;
    circularPrint(){
        pos=0;  
    }
    void shared_print(int threadID){
            unique_lock<mutex> locker(mu);
                if(pos+nCharsPerPrint<message.size())
                    cout<<"Thread"<<threadID<<" : "<<message.substr(pos,nCharsPerPrint)<<endl;      
                else if(pos<message.size())
                    cout<<"Thread"<<threadID<<" : "<<message.substr(pos)<<endl;
                pos+=nCharsPerPrint;
    }
};
void f(circularPrint &obj,int threadID){
    obj.shared_print(threadID);
}
int main(){
    circularPrint obj;
    cout<<"\nMessage : ";
    cin>>obj.message;
    cout<<"\nChars : ";
    cin>>obj.nCharsPerPrint;
    int nthreads;
    cout<<"\nThreads : ";
    cin>>nthreads;
    vector<thread> threads;
    for(int count=1;count<=nthreads;++count)
    {
        threads.push_back(thread(f,ref(obj),count));

    }

    for(int count=0;count<nthreads;++count)
    {
        if(threads[count].joinable())
            threads[count].join();
    }
    return 0;
}

3 个答案:

答案 0 :(得分:1)

为什么要多线程一次只能执行一次的方法?

无论如何,下面这样的话?请注意takeprint使用不同的锁,并且输出有可能不按预期顺序显示(因此,上面的原因问题)。

#include <iostream>
#include <mutex>
#include <thread>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;
class circularPrint
{
public:
    int pos;
    string message;
    int nCharsPerPrint;
    mutex takeLock;
    mutex printLock;
    circularPrint() {
        pos = 0;
    }

    string take(int count) {
        lock_guard<mutex> locker(takeLock);

        count = std::min(count, (int)message.size() - pos);
        string substring = message.substr(pos, count);
        pos += count;
        return substring;
    }

    void print(int threadID, string& message) {
        lock_guard<mutex> locker(printLock);
        cout << "Thread" << threadID << " : " << message << endl;
    }

    void loop(int threadID) {
        string message;

        while((message = take(nCharsPerPrint)).size() > 0) {
            print(threadID, message);
        }
    }
};




void f(circularPrint &obj, int threadID)
{
    obj.loop(threadID);
}
int main()
{
    circularPrint obj;
    //cout << "\nMessage : ";
    //cin >> obj.message;
    //cout << "\nChars : ";
    //cin >> obj.nCharsPerPrint;
    int nthreads;
    //cout << "\nThreads : ";
    //cin >> nthreads;

    nthreads = 4;
    obj.message = "123456789012345";
    obj.nCharsPerPrint = 2;

    vector<thread> threads;
    for (int count = 1; count <= nthreads; ++count)
        threads.push_back(thread(f, ref(obj), count));

    for (int count = 0; count < nthreads; ++count) {
        if (threads[count].joinable())
            threads[count].join();
    }
    return 0;
}

答案 1 :(得分:0)

你需要线程间同步,每个线程做一个循环“打印,向下一个发送消息,等待消息(从最后一个线程)”。
您可以使用信号量,事件,消息或类似的东西。

东西:

#include <string>
#include <iostream>
#include <condition_variable>
#include <thread>
#include <unistd.h>

using namespace std;

// Parameters passed to a thread.
struct ThreadParameters {
  string message;  // to print.
  volatile bool *exit;  // set when the thread should exit.
  condition_variable* input;  // condition to wait before printing.
  condition_variable* output;  // condition to set after printing.
};

class CircularPrint {
public:
  CircularPrint(int nb_threads) {
    nb_threads_ = nb_threads;
    condition_variables_ = new condition_variable[nb_threads];
    thread_parameters_ = new ThreadParameters[nb_threads];
    threads_ = new thread*[nb_threads];
    exit_ = false;
    for (int i = 0; i < nb_threads; ++i) {
      thread_parameters_[i].message = to_string(i + 1);
      thread_parameters_[i].exit = &exit_;
      // Wait 'your' condition
      thread_parameters_[i].input = &condition_variables_[i];
      // Then set next one (of first one if you are the last).
      thread_parameters_[i].output = 
          &condition_variables_[(i + 1) % nb_threads];
      threads_[i] = new thread(Thread, &thread_parameters_[i]);
    }
    // Start the dance, free the first thread.
    condition_variables_[0].notify_all();
  }

  ~CircularPrint() {
    // Ask threads to exit.
    exit_ = true;
    // Wait for all threads to end.
    for (int i = 0; i < nb_threads_; ++i) {
      threads_[i]->join();
      delete threads_[i];
    }
    delete[] condition_variables_;
    delete[] thread_parameters_;
    delete[] threads_;
  }

  static void Thread(ThreadParameters* params) {
    for (;;) {
      if (*params->exit) {
        return;
      }
      {
        // Wait the mutex. We don't really care, by condition variables
        // need a mutex.
        // Though the mutex will be useful for the real assignement.
        unique_lock<mutex> lock(mutex_);
        // Wait for the input condition variable (frees the mutex before waiting).
        params->input->wait(lock);
      }
      cout << params->message << endl;
      // Free next thread.
      params->output->notify_all();
    }      
  }

 private:
  int nb_threads_;
  condition_variable* condition_variables_;
  ThreadParameters* thread_parameters_;
  thread** threads_;
  bool exit_;
  static mutex mutex_;
};

mutex CircularPrint::mutex_;


int main() {
  CircularPrint printer(10);
  sleep(3);
  return 0;
}

使用vector<shared_ptr<...>>会比仅使用数组更优雅,但这有效:

g++ -std=c++11 -o test test.cc -pthread -Wl,--no-as-needed 
./test

答案 2 :(得分:0)

目前每个线程在打印一条消息后退出 - 但是您需要的消息多于线程,因此每个线程需要执行多条消息。

如何在当前锁定的部分周围设置无限循环,并在没有剩余字符打印时爆发?

(然后你可能会发现第一个线程完成了所有工作;你可以通过在锁定部分之外放置零长度睡眠,或者通过让所有线程等待某个单个信号启动,或者只是活着来破解它用它。)

编辑:没有意识到你想要将工作分配给特定的线程(这通常是一个非常糟糕的主意)。但是如果每个线程知道它的ID,以及它有多少,它可以找出它应该打印的字符。然后它所要做的就是等到所有前面的字符都被打印出来(它可以用pos告诉它),做它的工作,然后重复直到它没有工作要做并退出。

唯一棘手的问题是等待前面的工作完成。你可以通过忙碌的等待(糟糕),忙碌的等待(也是坏的)或条件变量(更好)来做到这一点。