对代码进行简单编辑(并已解决)
我希望能够创建一个带有自由的未绑定参数的打包任务,然后在调用打包任务时将其添加。
在这种情况下,我希望函数的第一个参数(类型为size_t
)不受约束。
这是一个可行的最小示例(这是解决方案):
#include <vector>
#include <queue>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <functional>
#include <stdexcept>
#include <cstdlib>
#include <cstdio>
//REV: I'm trying to "trick" this into for double testfunct( size_t arg1, double arg2), take enqueue( testfunct, 1.0 ), and then internally, execute
// return testfunct( internal_size_t, 1.0 )
template<typename F, typename... Args>
auto enqueue(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(size_t, Args...)>::type>
{
using return_type = typename std::result_of<F(size_t, Args...)>::type;
//REV: this is where the error was, I was being stupid and thinking this task_contents which would be pushed to the queue should be same (return?) type as original function? Changed to auto and everything worked... (taking into account Jans's result_type(size_t) advice into account.
//std::function<void(size_t)> task_contents = std::bind( std::forward<F>(f), std::placeholders::_1, std::forward<Args>(args)... );
auto task_contents = std::bind( std::forward<F>(f), std::placeholders::_1, std::forward<Args>(args)... );
std::packaged_task<return_type(size_t)> rawtask(
task_contents );
std::future<return_type> res = rawtask.get_future();
size_t arbitrary_i = 10;
rawtask(arbitrary_i);
return res;
}
double testfunct( size_t threadidx, double& arg1 )
{
fprintf(stdout, "Double %lf Executing on thread %ld\n", arg1, threadidx );
std::this_thread::sleep_for( std::chrono::milliseconds(1000) );
return 10; //true;
}
int main()
{
std::vector<std::future<double>> myfutures;
for(size_t x=0; x<100; ++x)
{
double a=x*10;
myfutures.push_back(
enqueue( testfunct, std::ref(a) )
);
}
for(size_t x=0; x<100; ++x)
{
double r = myfutures[x].get();
fprintf(stdout, "Got %ld: %f\n", x, r );
}
}
答案 0 :(得分:1)
主要问题在 public class User
{
public User()
{
}
public User(ClaimsPrincipal principal)
{
Id = principal.FindFirst(ClaimTypes.NameIdentifier).Value;
FirstName = principal.FindFirst(ClaimTypes.GivenName).Value;
Surname = principal.FindFirst(ClaimTypes.Surname).Value;
Email = principal.FindFirst(ClaimTypes.Email).Value;
}
[Key]
public string Id { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public bool Active { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime LastLoginTime { get; set; }
public Company Company { get; set; }
public User CreatedBy { get; set; }
//Hack to get around EF/Cosmos Enum error
private string UserType { get; set;}
[NotMapped]
public UserType UserTypeEnum
{
get
{
if (string.IsNullOrWhiteSpace(UserType))
{
return Models.UserType.User;
}
return (UserType)Enum.Parse(typeof(UserType), UserType);
}
set
{
UserType = value.ToString();
}
}
}
上:
ThreadPool::enqueue
在这里,std::function<void(size_t)> task1 = std::bind( std::forward<F>(f), std::placeholders::_1, std::forward<Args>(args)... );
的类型为task1
,但是用std::function<void(std::size_t)>
求值时std::bind
的结果可以转换为funct
,即使是@ TC指出,您可以将std::function<bool(std::size_t)>
的结果分配给bind
,为了将task1
传递给task1
,您需要兑现std::make_shared
已经。
将以上内容更改为:
return_type
现在相同:
std::function<return_type(size_t)> task1 = std::bind( std::forward<F>(f), std::placeholders::_1, std::forward<Args>(args)... );
,但是在这种情况下是缺少的参数类型。更改为:
auto task = std::make_shared< std::packaged_task<return_type()> >( task1 );
auto task = std::make_shared< std::packaged_task<return_type(std::size_t)> >( task1 );
存储类型为ThreadPool::tasks
的函数对象,但是您存储的lambda不接收任何参数。将std::function<void(std::size_t)>
更改为:
tasks.emplace(...)
答案 1 :(得分:1)
代码的格式不是很好,而是一种解决方案。
首先,您应该将结果包装在lambda创建中,而不是传递可以返回任何内容的函数。但是,如果要在任务上使用共享指针,则可以使用。
在原型中:
std::future<void> enqueue(std::function<void(size_t)> f);
using Task = std::function<void(size_t)>;
// the task queue
std::queue<Task> tasks;
std::optional<Task> pop_one();
实施变为:
ThreadPool::ThreadPool(size_t threads)
: stop(false)
{
for(size_t i = 0;i<threads;++i)
workers.emplace_back(
[this,i]
{
for(;;)
{
auto task = pop_one();
if(task)
{
(*task)(i);
}
else break;
}
}
);
}
std::optional<ThreadPool::Task> ThreadPool::pop_one()
{
std::unique_lock<std::mutex> lock(this->queue_mutex);
this->condition.wait(lock,
[this]{ return this->stop || !this->tasks.empty(); });
if(this->stop && this->tasks.empty())
{
return std::optional<Task>();
}
auto task = std::move(this->tasks.front()); //REV: this moves into my thread the front of the tasks queue.
this->tasks.pop();
return task;
}
template<typename T>
std::future<T> ThreadPool::enqueue(std::function<T(size_t)> fun)
{
auto task = std::make_shared< std::packaged_task<T(size_t)> >([=](size_t size){return fun(size);});
auto res = task->get_future();
{
std::unique_lock<std::mutex> lock(queue_mutex);
// don't allow enqueueing after stopping the pool
if(stop)
{
throw std::runtime_error("enqueue on stopped ThreadPool");
}
tasks.emplace([=](size_t size){(*task)(size);});
}
condition.notify_one();
return res;
}
现在您可以拥有自己的主要产品:
int main()
{
size_t nthreads=3;
ThreadPool tp(nthreads);
std::vector<std::future<bool>> myfutures;
for(size_t x=0; x<100; ++x)
{
myfutures.push_back(
tp.enqueue<bool>([=](size_t threadidx) {return funct(threadidx, (double)x * 10.0);}));
}
for(size_t x=0; x<100; ++x)
{
bool r = myfutures[x].get();
std::cout << "Got " << r << "\n";
}
}
现在,包装lambda时有一个显式的返回类型,因为返回类型是模板化的。